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 file COPYING.                     *
009 * COPYING can be found at the root of the source code distribution tree.    *
010 * If you do not have access to this file, you may request a copy from       *
011 * help@hdfgroup.org.                                                        *
012 ****************************************************************************/
013
014package hdf.view;
015
016import java.awt.BorderLayout;
017import java.awt.Color;
018import java.awt.Dimension;
019import java.awt.Graphics;
020import java.awt.GridLayout;
021import java.awt.Image;
022import java.awt.Insets;
023import java.awt.Point;
024import java.awt.Rectangle;
025import java.awt.Toolkit;
026import java.awt.event.ActionEvent;
027import java.awt.event.ActionListener;
028import java.awt.event.ItemEvent;
029import java.awt.event.ItemListener;
030import java.awt.event.KeyEvent;
031import java.awt.event.MouseEvent;
032import java.awt.event.MouseListener;
033import java.awt.event.MouseMotionListener;
034import java.util.BitSet;
035import java.util.List;
036import java.util.StringTokenizer;
037import java.util.Vector;
038
039import javax.swing.BorderFactory;
040import javax.swing.ButtonGroup;
041import javax.swing.JButton;
042import javax.swing.JCheckBox;
043import javax.swing.JComboBox;
044import javax.swing.JComponent;
045import javax.swing.JDialog;
046import javax.swing.JFrame;
047import javax.swing.JLabel;
048import javax.swing.JList;
049import javax.swing.JOptionPane;
050import javax.swing.JPanel;
051import javax.swing.JRadioButton;
052import javax.swing.JScrollPane;
053import javax.swing.JTextField;
054import javax.swing.JToggleButton;
055import javax.swing.SwingConstants;
056import javax.swing.WindowConstants;
057import javax.swing.border.EtchedBorder;
058import javax.swing.border.LineBorder;
059import javax.swing.border.TitledBorder;
060
061import hdf.object.CompoundDS;
062import hdf.object.Dataset;
063import hdf.object.Datatype;
064import hdf.object.FileFormat;
065import hdf.object.ScalarDS;
066
067/**
068 * DataOptionDialog is an dialog window used to select display options. Display options include
069 * selection of subset, display type (image, text, or spreadsheet).
070 *
071 * @author Peter X. Cao
072 * @version 2.4 9/6/2007
073 */
074public class DataOptionDialog extends JDialog implements ActionListener, ItemListener
075{
076    private static final long      serialVersionUID      = -1078411885690696784L;
077
078    /** The main HDFView. */
079    private final ViewManager      viewer;
080
081    /** the selected dataset/image */
082    private Dataset                dataset;
083
084    /** the rank of the dataset/image */
085    private int                    rank;
086
087    /** the starting point of selected subset */
088    private long                   start[];
089
090    /** the sizes of all dimensions */
091    private long                   dims[];
092
093    /** the selected sizes of all dimensions */
094    private long                   selected[];
095
096    /** the stride */
097    private long                   stride[];
098
099    /** the indices of the selected dimensions. */
100    private int                    selectedIndex[];
101
102    private int                    currentIndex[];
103
104    private BitSet                 bitmask;
105
106    private JRadioButton           spreadsheetButton, imageButton, base1Button, base0Button;
107    private JCheckBox              charCheckbox;
108    private JButton                bitmaskHelp;
109    private JCheckBox              applyBitmaskButton, extractBitButton;
110    private JRadioButton[]         bitmaskButtons;
111
112    @SuppressWarnings("rawtypes")
113    private JComboBox              choiceTextView;
114    @SuppressWarnings("rawtypes")
115    private JComboBox              choiceTableView;
116    @SuppressWarnings("rawtypes")
117    private JComboBox              choiceImageView;
118    @SuppressWarnings("rawtypes")
119    private JComboBox              choicePalette;
120    @SuppressWarnings("rawtypes")
121    private JComboBox              transposeChoice;
122    @SuppressWarnings("rawtypes")
123    private JComboBox              choices[];
124
125    private boolean                isSelectionCancelled;
126
127    private boolean                isTrueColorImage;
128
129    private boolean                isText;
130
131    private boolean                isH5;
132
133    private JLabel                 maxLabels[], selLabel;
134
135    private JTextField             startFields[], endFields[], strideFields[], dataRangeField, fillValueField;
136
137    @SuppressWarnings("rawtypes")
138    private JList                  fieldList;
139
140    private final Toolkit          toolkit;
141
142    private final PreviewNavigator navigator;
143
144    private int                    numberOfPalettes;
145
146    /**
147     * JComboBox.setSelectedItem() or setSelectedIndex() always fires action event. If you call
148     * setSelectedItem() or setSelectedIndex() at itemStateChanged() or actionPerformed(), the
149     * setSelectedItem() or setSelectedIndex() will make loop calls of itemStateChanged() or
150     * actionPerformed(). This is not what we want. We want the setSelectedItem() or
151     * setSelectedIndex() behavior like java.awt.Choice. This flag is used to serve this purpose.
152     */
153    private boolean                performJComboBoxEvent = false;
154
155    /**
156     * Constructs a DataOptionDialog with the given HDFView.
157     *
158     * @param theview The main HDFView
159     *
160     * @param theDataset The dataset to set display options for
161     */
162    @SuppressWarnings({ "rawtypes", "unchecked" })
163    public DataOptionDialog(ViewManager theview, Dataset theDataset) {
164        super((JFrame) theview, true);
165        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
166
167        viewer = theview;
168        dataset = theDataset;
169        isSelectionCancelled = true;
170        isTrueColorImage = false;
171        isText = false;
172        bitmask = null;
173        numberOfPalettes = 1;
174        toolkit = Toolkit.getDefaultToolkit();
175
176        if (dataset == null) {
177            dispose();
178        }
179        else {
180            setTitle("Dataset Selection - " + dataset.getPath()
181                    + dataset.getName());
182        }
183
184        isH5 = dataset.getFileFormat().isThisType(
185                FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5));
186
187        rank = dataset.getRank();
188        if (rank <= 0) {
189            dataset.init();
190        }
191        if (isH5 && (dataset instanceof ScalarDS)) {
192            byte[] palRefs = ((ScalarDS) dataset).getPaletteRefs();
193            if ((palRefs != null) && (palRefs.length > 8)) {
194                numberOfPalettes = palRefs.length / 8;
195            }
196        }
197        rank = dataset.getRank();
198        dims = dataset.getDims();
199        selected = dataset.getSelectedDims();
200        start = dataset.getStartDims();
201        selectedIndex = dataset.getSelectedIndex();
202        stride = dataset.getStride();
203        fieldList = null;
204
205        int h = 1, w = 1;
206        h = (int) dims[selectedIndex[0]];
207        if (rank > 1) {
208            w = (int) dims[selectedIndex[1]];
209        }
210
211        transposeChoice = new JComboBox();
212        transposeChoice.addItem("Reshape");
213        transposeChoice.addItem("Transpose");
214
215        selLabel = new JLabel("", SwingConstants.CENTER);
216        navigator = new PreviewNavigator(w, h);
217
218        currentIndex = new int[Math.min(3, rank)];
219
220        choicePalette = new JComboBox();
221        choicePalette.setName("modulepalette");
222        choiceTextView = new JComboBox((Vector<?>) HDFView.getListOfTextView());
223        choiceTextView.setName("moduletext");
224        choiceImageView = new JComboBox((Vector<?>) HDFView.getListOfImageView());
225        choiceImageView.setName("moduleimage");
226        choiceTableView = new JComboBox((Vector<?>) HDFView.getListOfTableView());
227        choiceTableView.setName("moduletable");
228
229        choicePalette.addItem("Select palette");
230        if (dataset instanceof ScalarDS) {
231            String paletteName = ((ScalarDS) dataset).getPaletteName(0);
232            if (paletteName == null) {
233                paletteName = "Default";
234            }
235            choicePalette.addItem(paletteName);
236            for (int i = 2; i <= numberOfPalettes; i++) {
237                paletteName = ((ScalarDS) dataset).getPaletteName(i - 1);
238                choicePalette.addItem(paletteName);
239            }
240        }
241        choicePalette.addItem("Gray");
242        choicePalette.addItem("ReverseGray");
243        choicePalette.addItem("GrayWave");
244        choicePalette.addItem("Rainbow");
245        choicePalette.addItem("Nature");
246        choicePalette.addItem("Wave");
247
248        spreadsheetButton = new JRadioButton("Spreadsheet ", true);
249        spreadsheetButton.setMnemonic(KeyEvent.VK_S);
250        spreadsheetButton.setName("spreadsheetbutton");
251        imageButton = new JRadioButton("Image ");
252        imageButton.setMnemonic(KeyEvent.VK_I);
253        imageButton.setName("imagebutton");
254
255        charCheckbox = new JCheckBox("Show As Char", false);
256        charCheckbox.setMnemonic(KeyEvent.VK_C);
257        charCheckbox.setEnabled(false);
258        charCheckbox.addItemListener(this);
259
260        extractBitButton = new JCheckBox("Show Value of Selected Bits", false);
261        extractBitButton.setMnemonic(KeyEvent.VK_V);
262        extractBitButton.setEnabled(false);
263        extractBitButton.addItemListener(this);
264
265        applyBitmaskButton = new JCheckBox("Apply Bitmask", false);
266        applyBitmaskButton.setMnemonic(KeyEvent.VK_A);
267        applyBitmaskButton.setEnabled(false);
268        applyBitmaskButton.addItemListener(this);
269        applyBitmaskButton.setName("applybitmask");
270
271        bitmaskHelp = new JButton(ViewProperties.getHelpIcon());
272        bitmaskHelp.setEnabled(false);
273        bitmaskHelp.setToolTipText("Help on how to set bitmask");
274        bitmaskHelp.setMargin(new Insets(0, 0, 0, 0));
275        bitmaskHelp.addActionListener(this);
276        bitmaskHelp.setActionCommand("Help on how to set bitmask");
277
278        // layout the components
279        JPanel contentPane = (JPanel) getContentPane();
280        contentPane.setLayout(new BorderLayout(5, 5));
281        contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
282        int w1 = 700 + (ViewProperties.getFontSize() - 12) * 15;
283        int h1 = 350 + (ViewProperties.getFontSize() - 12) * 10;
284        contentPane.setPreferredSize(new Dimension(w1, h1));
285
286        JPanel centerP = new JPanel();
287        centerP.setLayout(new BorderLayout());
288        TitledBorder tborder = new TitledBorder("Dimension and Subset Selection");
289        tborder.setTitleColor(Color.gray);
290        centerP.setBorder(tborder);
291
292        JPanel navigatorP = new JPanel();
293        navigatorP.setLayout(new BorderLayout());
294        navigatorP.add(navigator, BorderLayout.CENTER);
295        navigatorP.add(selLabel, BorderLayout.SOUTH);
296        navigatorP.setBorder(new EtchedBorder(EtchedBorder.LOWERED));
297        navigatorP.setName("navigator");
298        performJComboBoxEvent = true;
299
300        // create and initialize these buttons here so the isIndexBase1 method
301        // functions properly
302        base0Button = new JRadioButton("0-based ");
303        base1Button = new JRadioButton("1-based ");
304        if (ViewProperties.isIndexBase1())
305            base1Button.setSelected(true);
306        else
307            base0Button.setSelected(true);
308
309        if (dataset instanceof CompoundDS) {
310            // setup GUI components for the field selection
311            CompoundDS d = (CompoundDS) dataset;
312            String[] names = d.getMemberNames();
313            fieldList = new JList(names);
314            fieldList.addSelectionInterval(0, names.length - 1);
315            JPanel fieldP = new JPanel();
316            fieldP.setLayout(new BorderLayout());
317            w1 = 150 + (ViewProperties.getFontSize() - 12) * 10;
318            h1 = 250 + (ViewProperties.getFontSize() - 12) * 15;
319            fieldP.setPreferredSize(new Dimension(w1, h1));
320            JScrollPane scrollP = new JScrollPane(fieldList);
321            fieldP.add(scrollP);
322            tborder = new TitledBorder("Select Members");
323            tborder.setTitleColor(Color.gray);
324            fieldP.setBorder(tborder);
325            contentPane.add(fieldP, BorderLayout.WEST);
326
327            JPanel tviewP = new JPanel();
328            tviewP.setLayout(new BorderLayout());
329            tviewP.add(new JLabel("        TableView:  "), BorderLayout.WEST);
330            tviewP.add(choiceTableView, BorderLayout.CENTER);
331            tviewP.setBorder(new LineBorder(Color.LIGHT_GRAY));
332
333            centerP.add(tviewP, BorderLayout.SOUTH);
334        }
335        else if (dataset instanceof ScalarDS) {
336            ScalarDS sd = (ScalarDS) dataset;
337            isText = sd.isText();
338
339            if (isText) {
340                w1 = 700 + (ViewProperties.getFontSize() - 12) * 15;
341                h1 = 280 + (ViewProperties.getFontSize() - 12) * 10;
342                contentPane.setPreferredSize(new Dimension(w1, h1));
343                // add textview selection
344                JPanel txtviewP = new JPanel();
345                txtviewP.setLayout(new BorderLayout());
346                txtviewP.add(new JLabel("          TextView:  "),
347                        BorderLayout.WEST);
348                txtviewP.add(choiceTextView, BorderLayout.CENTER);
349                txtviewP.setBorder(new LineBorder(Color.LIGHT_GRAY));
350
351                centerP.add(txtviewP, BorderLayout.SOUTH);
352            }
353            else {
354                w1 = 800 + (ViewProperties.getFontSize() - 12) * 15;
355                h1 = 550 + (ViewProperties.getFontSize() - 12) * 10;
356                contentPane.setPreferredSize(new Dimension(w1, h1));
357                if (rank > 1) {
358                    centerP.add(navigatorP, BorderLayout.WEST);
359                }
360
361                // setup GUI components for the display options: table or image
362                imageButton.addItemListener(this);
363                spreadsheetButton.addItemListener(this);
364                ButtonGroup rgroup = new ButtonGroup();
365                rgroup.add(spreadsheetButton);
366                rgroup.add(imageButton);
367                JPanel viewP = new JPanel();
368                viewP.setLayout(new GridLayout(2, 1, 5, 5));
369                tborder = new TitledBorder("Display As");
370                tborder.setTitleColor(Color.gray);
371                viewP.setBorder(tborder);
372
373                JPanel sheetP = new JPanel();
374                sheetP.setLayout(new GridLayout(1, 2, 25, 5));
375                sheetP.add(spreadsheetButton);
376                int tclass = sd.getDatatype().getDatatypeClass();
377                sheetP.add(charCheckbox);
378                if (tclass == Datatype.CLASS_CHAR
379                        || (tclass == Datatype.CLASS_INTEGER && sd
380                                .getDatatype().getDatatypeSize() == 1)) {
381                    charCheckbox.setEnabled(false);
382                }
383
384                // add tableview selection
385                JPanel tviewP = new JPanel();
386                tviewP.setLayout(new BorderLayout());
387                tviewP.add(new JLabel("TableView:   "), BorderLayout.WEST);
388                tviewP.add(choiceTableView, BorderLayout.CENTER);
389
390                JPanel leftP = new JPanel();
391                leftP.setBorder(BorderFactory
392                        .createLineBorder(Color.LIGHT_GRAY));
393                leftP.setLayout(new GridLayout(2, 1, 5, 5));
394                leftP.add(sheetP);
395                leftP.add(tviewP);
396
397                viewP.add(leftP);
398
399                // add imageview selection
400                JPanel rightP = new JPanel();
401                rightP.setLayout(new BorderLayout(5, 5));
402                rightP.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY));
403                JPanel imageP1 = new JPanel();
404                JPanel imageP2 = new JPanel();
405                rightP.add(imageP1, BorderLayout.CENTER);
406                rightP.add(imageP2, BorderLayout.EAST);
407                viewP.add(rightP);
408                imageP1.setLayout(new BorderLayout(5, 5));
409                JPanel tmpP = new JPanel();
410                tmpP.setLayout(new GridLayout(2, 1, 5, 5));
411                tmpP.add(imageButton);
412                tmpP.add(new JLabel("ImageView: "));
413                imageP1.add(tmpP, BorderLayout.WEST);
414                tmpP = new JPanel();
415                tmpP.setLayout(new GridLayout(2, 1, 5, 5));
416                tmpP.add(choicePalette);
417                tmpP.add(choiceImageView);
418                imageP1.add(tmpP, BorderLayout.CENTER);
419
420                imageP2.setLayout(new GridLayout(1, 2, 5, 5));
421                tmpP = new JPanel();
422                tmpP.setLayout(new GridLayout(2, 1, 5, 5));
423                tmpP.add(new JLabel("  Valid Range: "));
424                tmpP.add(new JLabel("  Invalid Values:  "));
425                imageP2.add(tmpP);
426                tmpP = new JPanel();
427                tmpP.setLayout(new GridLayout(2, 1, 5, 5));
428                String minmaxStr = "min, max", fillStr = "val1, val2, ...";
429                double minmax[] = ((ScalarDS) dataset).getImageDataRange();
430                if (minmax != null) {
431                    if (dataset.getDatatype().getDatatypeClass() == Datatype.CLASS_FLOAT)
432                        minmaxStr = minmax[0] + "," + minmax[1];
433                    else
434                        minmaxStr = ((long) minmax[0]) + "," + ((long) minmax[1]);
435                }
436                List<Number> fillValue = ((ScalarDS) dataset).getFilteredImageValues();
437                int n = fillValue.size();
438                if (n > 0) {
439                    fillStr = fillValue.get(0).toString();
440                    for (int i = 1; i < n; i++) {
441                        fillStr += ", " + fillValue.get(i);
442                    }
443                }
444                tmpP.add(dataRangeField = new JTextField(minmaxStr));
445                tmpP.add(fillValueField = new JTextField(fillStr));
446                imageP2.add(tmpP);
447
448                JPanel northP = new JPanel();
449                northP.setLayout(new BorderLayout(5, 5));
450                northP.add(viewP, BorderLayout.CENTER);
451
452                // index base and bit mask
453                viewP = new JPanel();
454                viewP.setLayout(new BorderLayout());
455                northP.add(viewP, BorderLayout.SOUTH);
456
457                JPanel baseIndexP = new JPanel();
458                viewP.add(baseIndexP, BorderLayout.NORTH);
459                tborder = new TitledBorder("Index Base");
460                tborder.setTitleColor(Color.gray);
461                baseIndexP.setBorder(tborder);
462                baseIndexP.setLayout(new GridLayout(1, 2, 5, 5));
463
464                ButtonGroup bgrp = new ButtonGroup();
465                bgrp.add(base0Button);
466                bgrp.add(base1Button);
467
468                baseIndexP.add(base0Button);
469                baseIndexP.add(base1Button);
470
471                int tsize = sd.getDatatype().getDatatypeSize();
472                bitmaskButtons = (tsize >= 0) ? new JRadioButton[8 * tsize] : new JRadioButton[0];
473                for (int i = 0; i < bitmaskButtons.length; i++) {
474                    bitmaskButtons[i] = new JRadioButton(String.valueOf(i));
475                    bitmaskButtons[i].setEnabled(false);
476                    bitmaskButtons[i].addItemListener(this);
477                    bitmaskButtons[i].setName("bitmaskButton"+i);
478                }
479
480                JPanel sheetP2 = new JPanel();
481                viewP.add(sheetP2, BorderLayout.CENTER);
482                tborder = new TitledBorder("Bitmask");
483                tborder.setTitleColor(Color.gray);
484                sheetP2.setBorder(tborder);
485
486                tmpP = new JPanel();
487                if (bitmaskButtons.length <= 16) {
488                    tmpP.setLayout(new GridLayout(1, bitmaskButtons.length));
489                    for (int i = bitmaskButtons.length; i > 0; i--)
490                        tmpP.add(bitmaskButtons[i - 1]);
491                } else {
492                    tmpP.setLayout(new GridLayout(tsize/2, 16));
493                    for (int i = bitmaskButtons.length; i > 0; i--)
494                        tmpP.add(bitmaskButtons[i - 1]);
495                }
496
497                sheetP2.setLayout(new BorderLayout(10, 10));
498                if (tsize <= 8) sheetP2.add(tmpP, BorderLayout.CENTER);
499                sheetP2.add(new JLabel(), BorderLayout.NORTH);
500
501                JPanel tmpP2 = new JPanel();
502                tmpP2.setLayout(new GridLayout(2, 1));
503                tmpP2.add(extractBitButton);
504                tmpP2.add(applyBitmaskButton);
505                tmpP = new JPanel();
506                tmpP.setLayout(new BorderLayout());
507                tmpP.add(tmpP2, BorderLayout.WEST);
508                tmpP2 = new JPanel();
509                tmpP2.add(bitmaskHelp);
510                tmpP.add(tmpP2, BorderLayout.EAST);
511                sheetP2.add(tmpP, BorderLayout.NORTH);
512                contentPane.add(northP, BorderLayout.NORTH);
513
514                if (tclass == Datatype.CLASS_CHAR
515                        || (tclass == Datatype.CLASS_INTEGER && tsize <= 8)) {
516                    extractBitButton.setEnabled(true);
517                    applyBitmaskButton.setEnabled(true);
518                    bitmaskHelp.setEnabled(true);
519                }
520            }
521        }
522
523        // setup GUI for dimension and subset selection
524        JPanel selectionP = new JPanel();
525        selectionP.setLayout(new GridLayout(5, 6, 10, 3));
526        selectionP.setBorder(new EtchedBorder(EtchedBorder.LOWERED));
527
528        centerP.add(selectionP, BorderLayout.CENTER);
529        contentPane.add(centerP, BorderLayout.CENTER);
530
531        selectionP.add(new JLabel(" "));
532        if (rank > 1)
533            selectionP.add(transposeChoice);
534        else
535            selectionP.add(new JLabel(" "));
536
537        JLabel label = new JLabel("Start:");
538        selectionP.add(label);
539        label = new JLabel("End: ");
540        selectionP.add(label);
541        label = new JLabel("Stride:");
542        selectionP.add(label);
543        label = new JLabel("Max Size");
544        selectionP.add(label);
545
546        choices = new JComboBox[3];
547        maxLabels = new JLabel[3];
548        startFields = new JTextField[3];
549        endFields = new JTextField[3];
550        strideFields = new JTextField[3];
551        JLabel dimLabels[] = { new JLabel("Height", SwingConstants.RIGHT),
552                new JLabel("Width", SwingConstants.RIGHT),
553                new JLabel("Depth", SwingConstants.RIGHT), };
554
555        String[] dimNames = dataset.getDimNames();
556        for (int i = 0; i < 3; i++) {
557            choices[i] = new JComboBox();
558            choices[i].addItemListener(this);
559            for (int j = 0; j < rank; j++) {
560                if (dimNames == null) {
561                    choices[i].addItem("dim " + j);
562                }
563                else {
564                    choices[i].addItem(dimNames[j]);
565                }
566            }
567            maxLabels[i] = new JLabel("1");
568            startFields[i] = new JTextField("0");
569            endFields[i] = new JTextField("0");
570            strideFields[i] = new JTextField("1");
571            selectionP.add(dimLabels[i]);
572            selectionP.add(choices[i]);
573            selectionP.add(startFields[i]);
574            selectionP.add(endFields[i]);
575            selectionP.add(strideFields[i]);
576            selectionP.add(maxLabels[i]);
577
578            // disable the selection components
579            // init() will set them appropriate
580            choices[i].setEnabled(false);
581            startFields[i].setEnabled(false);
582            endFields[i].setEnabled(false);
583            strideFields[i].setEnabled(false);
584            maxLabels[i].setEnabled(false);
585
586            // Provide fields with names for access
587            startFields[i].setName("startField"+i);
588            endFields[i].setName("endField"+i);
589            strideFields[i].setName("strideField"+i);
590            choices[i].setName("dimensionBox"+i);
591        }
592
593        // add button dimension selection when dimension size >= 4
594        JButton button = new JButton("dims...");
595        selectionP.add(new JLabel("", SwingConstants.RIGHT));
596        selectionP.add(button);
597
598        button.setActionCommand("Select more dimensions");
599        button.addActionListener(this);
600        button.setEnabled((rank > 3));
601        selectionP.add(new JLabel(" "));
602        selectionP.add(new JLabel(" "));
603        button = new JButton("Reset");
604        button.setName("Reset");
605        button.setActionCommand("Reset data range");
606        button.addActionListener(this);
607        selectionP.add(button);
608        selectionP.add(new JLabel(" "));
609
610        // add OK and CANCEL buttons
611        JPanel confirmP = new JPanel();
612        contentPane.add(confirmP, BorderLayout.SOUTH);
613        button = new JButton("   Ok   ");
614        button.setName("OK");
615        button.setMnemonic(KeyEvent.VK_O);
616        button.setActionCommand("Ok");
617        button.addActionListener(this);
618        confirmP.add(button);
619        button = new JButton("Cancel");
620        button.setName("Cancel");
621        button.setMnemonic(KeyEvent.VK_C);
622        button.setActionCommand("Cancel");
623        button.addActionListener(this);
624        confirmP.add(button);
625
626        init();
627
628        // locate the H5Property dialog
629        Point l = getParent().getLocation();
630        l.x += 250;
631        l.y += 80;
632        setLocation(l);
633        pack();
634    }
635
636    @Override
637    public void actionPerformed (ActionEvent e) {
638        String cmd = e.getActionCommand();
639
640        if (cmd.equals("Ok")) {
641            // set palette for image view
642            if ((dataset instanceof ScalarDS) && imageButton.isSelected()) {
643                setPalette();
644            }
645
646            isSelectionCancelled = !setSelection();
647
648            if (isSelectionCancelled) {
649                return;
650            }
651
652            if (dataset instanceof ScalarDS) {
653                ((ScalarDS) dataset).setIsImageDisplay(imageButton.isSelected());
654            }
655
656            dispose();
657        }
658        else if (cmd.equals("Cancel")) {
659            dispose();
660        }
661        else if (cmd.equals("Reset data range")) {
662            int n = startFields.length;
663
664            for (int i = 0; i < n; i++) {
665                startFields[i].setText("0");
666                strideFields[i].setText("1");
667                long l = Long.valueOf(maxLabels[i].getText()) - 1;
668                endFields[i].setText(String.valueOf(l));
669            }
670        }
671        else if (cmd.equals("Select more dimensions")) {
672            if (rank < 4) {
673                return;
674            }
675
676            int idx = 0;
677            Vector<Object> choice4 = new Vector<Object>(rank);
678            int[] choice4Index = new int[rank - 3];
679            for (int i = 0; i < rank; i++) {
680                if ((i != currentIndex[0]) && (i != currentIndex[1])
681                        && (i != currentIndex[2])) {
682                    choice4.add(choices[0].getItemAt(i));
683                    choice4Index[idx++] = i;
684                }
685            }
686
687            String msg = "Select slice location for dimension(s):\n\""
688                    + choice4.get(0) + " [0 .. " + (dims[choice4Index[0]] - 1)
689                    + "]\"";
690            String initValue = String.valueOf(start[choice4Index[0]]);
691            int n = choice4.size();
692            for (int i = 1; i < n; i++) {
693                msg += " x \"" + choice4.get(i) + " [0 .. "
694                        + (dims[choice4Index[i]] - 1) + "]\"";
695                initValue += " x " + String.valueOf(start[choice4Index[i]]);
696            }
697
698            String result = JOptionPane.showInputDialog(this, msg, initValue);
699            if ((result == null) || ((result = result.trim()) == null)
700                    || (result.length() < 1)) {
701                return;
702            }
703
704            StringTokenizer st = new StringTokenizer(result, "x");
705            if (st.countTokens() < n) {
706                JOptionPane.showMessageDialog(this,
707                        "Number of dimension(s) is less than " + n + "\n"
708                                + result, "Select Slice Location",
709                        JOptionPane.ERROR_MESSAGE);
710                return;
711            }
712
713            long[] start4 = new long[n];
714            for (int i = 0; i < n; i++) {
715                try {
716                    start4[i] = Long.parseLong(st.nextToken().trim());
717                }
718                catch (Exception ex) {
719                    JOptionPane.showMessageDialog(this, ex.getMessage(),
720                            "Select Slice Location", JOptionPane.ERROR_MESSAGE);
721                    return;
722                }
723
724                if ((start4[i] < 0) || (start4[i] >= dims[choice4Index[i]])) {
725                    JOptionPane.showMessageDialog(this,
726                            "Slice location is out of range.\n" + start4[i]
727                                    + " >= " + dims[choice4Index[i]],
728                            "Select Slice Location", JOptionPane.ERROR_MESSAGE);
729                    return;
730                }
731
732            }
733
734            for (int i = 0; i < n; i++) {
735                start[choice4Index[i]] = start4[i];
736            }
737        } // else if (cmd.equals("Select more dimensions"))
738        else if (cmd.equals("Help on how to set bitmask")) {
739            String msg = ""
740                    + "\"Apply Bitmask\" applies bitwise \"AND\" to the original data.\n"
741                    + "For example, bits 2, 3, and 4 are selected for the bitmask\n"
742                    + "         10010101 (data)\n"
743                    + "AND 00011100 (mask)  \n"
744                    + "  =     00010100 (result) ==> the decimal value is 20. \n"
745                    + "\n"
746                    + "\"Extract Bit(s)\" removes all the bits from the result above where\n"
747                    + "their corresponding bits in the bitmask are 0. \nFor the same example above, "
748                    + "the result is \n101 ==> the decimal value is 5.\n\n";
749
750            JOptionPane.showMessageDialog((JFrame) viewer, msg);
751        }
752    }
753
754    @Override
755    public void itemStateChanged (ItemEvent e) {
756        Object source = e.getSource();
757
758        if (source.equals(imageButton)) {
759            choicePalette.setEnabled(!isTrueColorImage);
760            dataRangeField.setEnabled(true);
761            fillValueField.setEnabled(true);
762            choiceImageView.setEnabled(true);
763            choiceTableView.setEnabled(false);
764            charCheckbox.setSelected(false);
765            charCheckbox.setEnabled(false);
766        }
767        else if (source.equals(spreadsheetButton)) {
768            choicePalette.setEnabled(false);
769            choiceImageView.setEnabled(false);
770            choiceTableView.setEnabled(true);
771            dataRangeField.setEnabled(false);
772            fillValueField.setEnabled(false);
773            Datatype dtype = dataset.getDatatype();
774            int tclass = dtype.getDatatypeClass();
775            charCheckbox.setEnabled((tclass == Datatype.CLASS_CHAR ||
776                    tclass == Datatype.CLASS_INTEGER) &&
777                    (dtype.getDatatypeSize() == 1));
778        }
779        else if (source instanceof JToggleButton) {
780            checkBitmaskButtons((JToggleButton) source);
781        }
782        else if (source instanceof JComboBox) {
783            if (!performJComboBoxEvent) {
784                return;
785            }
786
787            if (e.getStateChange() == ItemEvent.DESELECTED) {
788                return; // don't care about the deselect
789            }
790
791            @SuppressWarnings("rawtypes")
792            JComboBox theChoice = (JComboBox) source;
793
794            int theSelectedChoice = -1;
795
796            int n = Math.min(3, rank);
797            for (int i = 0; i < n; i++) {
798                if (theChoice.equals(choices[i])) {
799                    theSelectedChoice = i;
800                }
801            }
802
803            if (theSelectedChoice < 0) {
804                return; // the selected JComboBox is not a dimension choice
805            }
806
807            int theIndex = theChoice.getSelectedIndex();
808            if (theIndex == currentIndex[theSelectedChoice]) {
809                return; // select the same item, no change
810            }
811
812            start[currentIndex[theSelectedChoice]] = 0;
813
814            // reset the selected dimension choice
815            startFields[theSelectedChoice].setText("0");
816            endFields[theSelectedChoice].setText(String
817                    .valueOf(dims[theIndex] - 1));
818            strideFields[theSelectedChoice].setText("1");
819            maxLabels[theSelectedChoice]
820                    .setText(String.valueOf(dims[theIndex]));
821
822            // if the selected choice selects the dimension that is selected by
823            // other dimension choice, exchange the dimensions
824            for (int i = 0; i < n; i++) {
825                if (i == theSelectedChoice) {
826                    continue; // don't exchange itself
827                }
828                else if (theIndex == choices[i].getSelectedIndex()) {
829                    setJComboBoxSelectedIndex(choices[i],
830                            currentIndex[theSelectedChoice]);
831                    startFields[i].setText("0");
832                    endFields[i]
833                            .setText(String
834                                    .valueOf(dims[currentIndex[theSelectedChoice]] - 1));
835                    strideFields[i].setText("1");
836                    maxLabels[i].setText(String
837                            .valueOf(dims[currentIndex[theSelectedChoice]]));
838                }
839            }
840
841            for (int i = 0; i < n; i++) {
842                currentIndex[i] = choices[i].getSelectedIndex();
843            }
844
845            // update the navigator
846            if (rank > 1) {
847                if (isText) {
848                    endFields[1].setText(startFields[1].getText());
849                }
850                else {
851                    int hIdx = choices[0].getSelectedIndex();
852                    int wIdx = choices[1].getSelectedIndex();
853                    transposeChoice.setSelectedIndex(0);
854
855                    // Use transpose option only if the dims are not in original
856                    // order
857                    if (hIdx < wIdx)
858                        transposeChoice.setEnabled(false);
859                    else
860                        transposeChoice.setEnabled(true);
861
862                    long dims[] = dataset.getDims();
863                    int w = (int) dims[wIdx];
864                    int h = (int) dims[hIdx];
865                    navigator.setDimensionSize(w, h);
866                    navigator.updateUI();
867                }
868            }
869
870            if (rank > 2) {
871                endFields[2].setText(startFields[2].getText());
872            }
873        } // else if (source instanceof JComboBox)
874    }
875
876    /**
877     * Returns true if the data selection is cancelled.
878     *
879     * @return true if the data selection is cancelled; false otherwise
880     */
881    public boolean isCancelled ( ) {
882        return isSelectionCancelled;
883    }
884
885    /**
886     * Returns true if the display option is image.
887     *
888     * @return true if the display option is image; false otherwise
889     */
890    public boolean isImageDisplay ( ) {
891        return imageButton.isSelected();
892    }
893
894    public boolean isIndexBase1 ( ) {
895        if (base1Button == null)
896            return false;
897
898        return base1Button.isSelected();
899    }
900
901    /** for deal with bit masks only */
902    private void checkBitmaskButtons (JToggleButton source) {
903        boolean b = false;
904        int n = 0;
905
906        if (source.equals(applyBitmaskButton)) {
907            if (applyBitmaskButton.isSelected())
908                extractBitButton.setSelected(false);
909        }
910        else if (source.equals(extractBitButton)) {
911            if (extractBitButton.isSelected())
912                applyBitmaskButton.setSelected(false);
913        }
914
915        b = (applyBitmaskButton.isSelected() || extractBitButton.isSelected());
916        bitmaskButtons[0].setEnabled(b);
917        if (bitmaskButtons[0].isSelected())
918            n = 1;
919
920        for (int i = 1; i < bitmaskButtons.length; i++) {
921            bitmaskButtons[i].setEnabled(b);
922            if (bitmaskButtons[i].isSelected() && !bitmaskButtons[i - 1].isSelected())
923                n++;
924        }
925
926        // do not allow non-adjacent selection for extracting bits
927        if (extractBitButton.isSelected() && n > 1) {
928            if (source.equals(extractBitButton) && extractBitButton.isSelected()) {
929                applyBitmaskButton.setSelected(true);
930                JOptionPane.showMessageDialog(this,
931                        "Selecting non-adjacent bits is only allowed \nfor the \"Apply Bitmask\" option.",
932                        "Select Bitmask",
933                        JOptionPane.ERROR_MESSAGE);
934            }
935            else if (source instanceof JRadioButton) {
936                JOptionPane.showMessageDialog(this,
937                        "Please select contiguous bits \nwhen the \"Show Value of Selected Bits\" option is checked.",
938                        "Select Bitmask",
939                        JOptionPane.ERROR_MESSAGE);
940                source.setSelected(false);
941            }
942        } // if (extractBitButton.isSelected() && n>1) {
943    }
944
945    /**
946     * Set the initial state of all the variables
947     */
948    private void init ( ) {
949        // set the imagebutton state
950        boolean isImage = false;
951
952        if (dataset instanceof ScalarDS) {
953            if(!((ScalarDS) dataset).isText()) {
954                ScalarDS sd = (ScalarDS) dataset;
955                isImage = sd.isImageDisplay();
956                isTrueColorImage = sd.isTrueColor();
957                // compound datasets don't have data range or fill values
958                // (JAVA-1825)
959                dataRangeField.setEnabled(isImage);
960                fillValueField.setEnabled(isImage);
961            }
962        }
963        else if (dataset instanceof CompoundDS) {
964            imageButton.setEnabled(false);
965        }
966
967        choiceTableView.setEnabled(!isImage);
968        choiceImageView.setEnabled(isImage);
969        imageButton.setSelected(isImage);
970        choicePalette.setEnabled(isImage && !isTrueColorImage);
971
972        int n = Math.min(3, rank);
973        long endIdx = 0;
974        for (int i = 0; i < n; i++) {
975            choices[i].setEnabled(true);
976            startFields[i].setEnabled(true);
977            endFields[i].setEnabled(true);
978            strideFields[i].setEnabled(true);
979            maxLabels[i].setEnabled(true);
980
981            int idx = selectedIndex[i];
982            endIdx = start[idx] + selected[idx] * stride[idx];
983            if (endIdx >= dims[idx]) {
984                endIdx = dims[idx];
985            }
986
987            setJComboBoxSelectedIndex(choices[i], idx);
988            maxLabels[i].setText(String.valueOf(dims[idx]));
989            startFields[i].setText(String.valueOf(start[idx]));
990            endFields[i].setText(String.valueOf(endIdx - 1));
991
992            if (!isH5 && (dataset instanceof CompoundDS)) {
993                strideFields[i].setEnabled(false);
994            }
995            else {
996                strideFields[i].setText(String.valueOf(stride[idx]));
997            }
998        }
999
1000        if (rank > 1) {
1001            transposeChoice.setEnabled((choices[0].getSelectedIndex() > choices[1].getSelectedIndex()));
1002
1003            if (isText) {
1004                endFields[1].setEnabled(false);
1005                endFields[1].setText(startFields[1].getText());
1006            }
1007        }
1008
1009        if (rank > 2) {
1010            endFields[2].setEnabled(false);
1011            strideFields[2].setEnabled(false);
1012            if (isTrueColorImage && imageButton.isSelected()) {
1013                choices[0].setEnabled(false);
1014                choices[1].setEnabled(false);
1015                choices[2].setEnabled(false);
1016                startFields[2].setEnabled(false);
1017                startFields[2].setText("0");
1018                endFields[2].setText("0");
1019            }
1020            else {
1021                choices[0].setEnabled(true);
1022                choices[1].setEnabled(true);
1023                choices[2].setEnabled(true);
1024                startFields[2].setEnabled(true);
1025                startFields[2].setText(String.valueOf(start[selectedIndex[2]]));
1026                // endFields[2].setEnabled(!isText);
1027                endFields[2].setText(startFields[2].getText());
1028            }
1029        }
1030
1031        for (int i = 0; i < n; i++) {
1032            currentIndex[i] = choices[i].getSelectedIndex();
1033        }
1034
1035        // reset show char button
1036        Datatype dtype = dataset.getDatatype();
1037        int tclass = dtype.getDatatypeClass();
1038        if (tclass == Datatype.CLASS_CHAR || tclass == Datatype.CLASS_INTEGER) {
1039            int tsize = dtype.getDatatypeSize();
1040            charCheckbox.setEnabled((tsize == 1) && spreadsheetButton.isSelected());
1041            extractBitButton.setEnabled(tsize <= 8);
1042            applyBitmaskButton.setEnabled(tsize <= 8);
1043        }
1044        else {
1045            charCheckbox.setEnabled(false);
1046            charCheckbox.setSelected(false);
1047            extractBitButton.setEnabled(false);
1048            applyBitmaskButton.setEnabled(false);
1049        }
1050    }
1051
1052    /**
1053     * JComboBox.setSelectedItem() or setSelectedIndex() always fires action event. If you call
1054     * setSelectedItem() or setSelectedIndex() at itemStateChanged() or actionPerformed(), the
1055     * setSelectedItem() or setSelectedIndex() will make loop calls of itemStateChanged() or
1056     * actionPerformed(). This is not what we want. We want the setSelectedItem() or
1057     * setSelectedIndex() behavior like java.awt.Choice. This flag is used to serve this purpose.
1058     */
1059    @SuppressWarnings("rawtypes")
1060    private void setJComboBoxSelectedIndex (JComboBox box, int idx) {
1061        performJComboBoxEvent = false;
1062        box.setSelectedIndex(idx);
1063        performJComboBoxEvent = true;
1064    }
1065
1066    private void setPalette ( ) {
1067        if (!(dataset instanceof ScalarDS)) {
1068            return;
1069        }
1070
1071        byte[][] pal = null;
1072        int palChoice = choicePalette.getSelectedIndex();
1073
1074        if (palChoice == 0) {
1075            return; /* using default palette */
1076        }
1077
1078        if (palChoice == numberOfPalettes + 1) {
1079            pal = Tools.createGrayPalette();
1080        }
1081        else if (palChoice == numberOfPalettes + 2) {
1082            pal = Tools.createReverseGrayPalette();
1083        }
1084        else if (palChoice == numberOfPalettes + 3) {
1085            pal = Tools.createGrayWavePalette();
1086        }
1087        else if (palChoice == numberOfPalettes + 4) {
1088            pal = Tools.createRainbowPalette();
1089        }
1090        else if (palChoice == numberOfPalettes + 5) {
1091            pal = Tools.createNaturePalette();
1092        }
1093        else if (palChoice == numberOfPalettes + 6) {
1094            pal = Tools.createWavePalette();
1095        }
1096        else if ((palChoice > 0) && (palChoice <= numberOfPalettes)) {
1097            // multiple palettes attached
1098            pal = ((ScalarDS) dataset).readPalette(palChoice - 1);
1099        }
1100
1101        ((ScalarDS) dataset).setPalette(pal);
1102    }
1103
1104    private boolean setSelection ( ) {
1105        long[] n0 = { 0, 0, 0 }; // start
1106        long[] n1 = { 0, 0, 0 }; // end
1107        long[] n2 = { 1, 1, 1 }; // stride
1108        int[] sIndex = { 0, 1, 2 };
1109        boolean retVal = true;
1110
1111        int n = Math.min(3, rank);
1112        for (int i = 0; i < n; i++) {
1113            sIndex[i] = choices[i].getSelectedIndex();
1114
1115            try {
1116                n0[i] = Long.parseLong(startFields[i].getText());
1117                if (i < 2) {
1118                    n1[i] = Long.parseLong(endFields[i].getText());
1119                    n2[i] = Long.parseLong(strideFields[i].getText());
1120                }
1121            }
1122            catch (NumberFormatException ex) {
1123                toolkit.beep();
1124                JOptionPane.showMessageDialog((JFrame) viewer, ex.getMessage(),
1125                        getTitle(), JOptionPane.ERROR_MESSAGE);
1126                return false;
1127            }
1128
1129            // silently correct errors
1130            if (n0[i] < 0) {
1131                n0[i] = 0; // start
1132            }
1133            if (n0[i] >= dims[sIndex[i]]) {
1134                n0[i] = dims[sIndex[i]] - 1;
1135            }
1136            if (n1[i] < 0) {
1137                n1[i] = 0; // end
1138            }
1139            if (n1[i] >= dims[sIndex[i]]) {
1140                n1[i] = dims[sIndex[i]] - 1;
1141            }
1142            if (n0[i] > n1[i]) {
1143                n1[i] = n0[i]; // end <= start
1144            }
1145            if (n2[i] > dims[sIndex[i]]) {
1146                n2[i] = dims[sIndex[i]];
1147            }
1148            if (n2[i] <= 0) {
1149                n2[i] = 1; // stride cannot be zero
1150            }
1151        } // for (int i=0; i<n; i++)
1152
1153        if (dataset instanceof CompoundDS) {
1154            CompoundDS d = (CompoundDS) dataset;
1155            int[] selectedFieldIndices = fieldList.getSelectedIndices();
1156            if ((selectedFieldIndices == null)
1157                    || (selectedFieldIndices.length < 1)) {
1158                toolkit.beep();
1159                JOptionPane.showMessageDialog((JFrame) viewer,
1160                        "No member/field is selected.", getTitle(),
1161                        JOptionPane.ERROR_MESSAGE);
1162                return false;
1163            }
1164
1165            d.setMemberSelection(false); // deselect all members
1166            for (int i = 0; i < selectedFieldIndices.length; i++) {
1167                d.selectMember(selectedFieldIndices[i]);
1168            }
1169        }
1170        else {
1171            ScalarDS ds = (ScalarDS) dataset;
1172
1173            if(!ds.isText()) {
1174                StringTokenizer st = new StringTokenizer(dataRangeField.getText(), ",");
1175                if (st.countTokens() == 2) {
1176                    double min = 0, max = 0;
1177                    try {
1178                        min = Double.valueOf(st.nextToken());
1179                        max = Double.valueOf(st.nextToken());
1180                    }
1181                    catch (Throwable ex) {
1182                    }
1183                    if (max > min)
1184                        ds.setImageDataRange(min, max);
1185                }
1186                st = new StringTokenizer(fillValueField.getText(), ",");
1187                while (st.hasMoreTokens()) {
1188                    double x = 0;
1189                    try {
1190                        x = Double.valueOf(st.nextToken());
1191                        ds.addFilteredImageValue(x);
1192                    }
1193                    catch (Throwable ex) {
1194                    }
1195                }
1196            }
1197        }
1198
1199        // reset selected size
1200        for (int i = 0; i < rank; i++) {
1201            selected[i] = 1;
1202            stride[i] = 1;
1203        }
1204
1205        // find no error, set selection the the dataset object
1206        for (int i = 0; i < n; i++) {
1207            selectedIndex[i] = sIndex[i];
1208            start[selectedIndex[i]] = n0[i];
1209            if (i < 2) {
1210                selected[selectedIndex[i]] = (int) ((n1[i] - n0[i]) / n2[i]) + 1;
1211                stride[selectedIndex[i]] = n2[i];
1212            }
1213        }
1214
1215        if ((rank > 1) && isText) {
1216            selected[selectedIndex[1]] = 1;
1217            stride[selectedIndex[1]] = 1;
1218        }
1219        else if ((rank > 2) && isTrueColorImage && imageButton.isSelected()) {
1220            start[selectedIndex[2]] = 0;
1221            selected[selectedIndex[2]] = 3;
1222        }
1223
1224        // clear the old data
1225        dataset.clearData();
1226
1227        retVal = setBitmask();
1228
1229        return retVal;
1230    }
1231
1232    private boolean setBitmask() {
1233        boolean isAll = false, isNothing = false;
1234
1235        if (bitmaskButtons == null) {
1236            bitmask = null;
1237            return true;
1238        }
1239
1240        if (!(applyBitmaskButton.isSelected() || extractBitButton.isSelected())) {
1241            bitmask = null;
1242            return true;
1243        }
1244
1245        int len = bitmaskButtons.length;
1246        for (int i = 0; i < len; i++) {
1247            isAll = (isAll && bitmaskButtons[i].isSelected());
1248            isNothing = (isNothing && !bitmaskButtons[i].isSelected());
1249        }
1250
1251        if (isAll || isNothing) {
1252            bitmask = null;
1253            return true;
1254        }
1255
1256        if (bitmask == null)
1257            bitmask = new BitSet(len);
1258
1259        for (int i = 0; i < len; i++) {
1260            bitmask.set(i, bitmaskButtons[i].isSelected());
1261        }
1262
1263        return true;
1264    }
1265
1266    /** SubsetNavigator draws selection rectangle of subset. */
1267    private class PreviewNavigator extends JComponent implements MouseListener,
1268            MouseMotionListener {
1269        private static final long serialVersionUID = -4458114008420664965L;
1270        private final int         NAVIGATOR_SIZE   = 150;
1271        private int               dimX, dimY, x, y;
1272        private double            r;
1273        private Point             startPosition;                           // mouse clicked position
1274        private Rectangle         selectedArea;
1275        private Image             previewImage     = null;
1276
1277        private PreviewNavigator(int w, int h) {
1278            dimX = w;
1279            dimY = h;
1280            if (dimX > dimY) {
1281                x = NAVIGATOR_SIZE;
1282                r = dimX / (double) x;
1283                y = (int) (dimY / r);
1284            }
1285            else {
1286                y = NAVIGATOR_SIZE;
1287                r = dimY / (double) y;
1288                x = (int) (dimX / r);
1289            }
1290
1291            selectedArea = new Rectangle();
1292            setPreferredSize(new Dimension(NAVIGATOR_SIZE, NAVIGATOR_SIZE));
1293            try {
1294                previewImage = createPreviewImage();
1295            }
1296            catch (Exception ex) {
1297                ex.printStackTrace();
1298            }
1299
1300            addMouseListener(this);
1301            addMouseMotionListener(this);
1302        }
1303
1304        private Image createPreviewImage ( ) throws Exception {
1305            if ((rank <= 1) || !(dataset instanceof ScalarDS)) {
1306                return null;
1307            }
1308
1309            Image preImage = null;
1310            ScalarDS sd = (ScalarDS) dataset;
1311
1312            if (sd.isText()) {
1313                return null;
1314            }
1315
1316            // backup the selection
1317            long[] strideBackup = new long[rank];
1318            long[] selectedBackup = new long[rank];
1319            long[] startBackup = new long[rank];
1320            int[] selectedIndexBackup = new int[3];
1321            System.arraycopy(stride, 0, strideBackup, 0, rank);
1322            System.arraycopy(selected, 0, selectedBackup, 0, rank);
1323            System.arraycopy(start, 0, startBackup, 0, rank);
1324            System.arraycopy(selectedIndex, 0, selectedIndexBackup, 0, 3);
1325
1326            // set the selection for preview
1327            for (int i = 0; i < rank; i++) {
1328                start[i] = 0;
1329                stride[i] = 1;
1330                selected[i] = 1;
1331            }
1332
1333            if (choices != null) {
1334                try {
1335                    selectedIndex[0] = choices[0].getSelectedIndex();
1336                    selectedIndex[1] = choices[1].getSelectedIndex();
1337                }
1338                catch (Exception ex) {
1339                }
1340            }
1341            long steps = (long) Math.ceil(r);
1342            selected[selectedIndex[0]] = (dims[selectedIndex[0]] / steps);
1343            selected[selectedIndex[1]] = (dims[selectedIndex[1]] / steps);
1344            stride[selectedIndex[0]] = stride[selectedIndex[1]] = steps;
1345
1346            if (selected[selectedIndex[0]] == 0) {
1347                selected[selectedIndex[0]] = 1;
1348            }
1349            if (selected[selectedIndex[1]] == 0) {
1350                selected[selectedIndex[1]] = 1;
1351            }
1352
1353            if (isTrueColorImage && (start.length > 2)) {
1354                start[selectedIndex[2]] = 0;
1355                selected[selectedIndex[2]] = 3;
1356                stride[selectedIndex[2]] = 1;
1357            }
1358
1359            // update the ratio of preview image size to the real dataset
1360            y = (int) selected[selectedIndex[0]];
1361            x = (int) selected[selectedIndex[1]];
1362            r = Math.min((double) dims[selectedIndex[0]]
1363                    / (double) selected[selectedIndex[0]],
1364                    (double) dims[selectedIndex[1]]
1365                            / (double) selected[selectedIndex[1]]);
1366
1367            try {
1368                Object data = sd.read();
1369                int h = sd.getHeight();
1370                int w = sd.getWidth();
1371
1372                byte[] bData = Tools.getBytes(data, sd.getImageDataRange(), w, h, false, sd.getFilteredImageValues(), null);
1373
1374                if (isTrueColorImage) {
1375                    boolean isPlaneInterlace = (sd.getInterlace() == ScalarDS.INTERLACE_PLANE);
1376                    preImage = Tools.createTrueColorImage(bData,
1377                            isPlaneInterlace, w, h);
1378                }
1379                else {
1380                    byte[][] imagePalette = sd.getPalette();
1381                    if (imagePalette == null) {
1382                        imagePalette = Tools.createGrayPalette();
1383                    }
1384
1385                    if ((isH5 || (rank > 2))
1386                            && (selectedIndex[0] > selectedIndex[1])) {
1387                        // transpose data
1388                        int n = bData.length;
1389                        byte[] bData2 = new byte[n];
1390                        for (int i = 0; i < h; i++) {
1391                            for (int j = 0; j < w; j++) {
1392                                bData[i * w + j] = bData2[j * h + i];
1393                            }
1394                        }
1395                    }
1396                    if (!isH5 && !sd.isDefaultImageOrder() && (selectedIndex[1] > selectedIndex[0])) {
1397                        // transpose data for hdf4 images where selectedIndex[1]
1398                        // > selectedIndex[0]
1399                        int n = bData.length;
1400                        byte[] bData2 = new byte[n];
1401                        for (int i = 0; i < h; i++) {
1402                            for (int j = 0; j < w; j++) {
1403                                bData[i * w + j] = bData2[j * h + i];
1404                            }
1405                        }
1406                    }
1407                    preImage = Tools.createIndexedImage(null, bData, imagePalette, w, h);
1408                }
1409            }
1410            finally {
1411                // set back the original selection
1412                System.arraycopy(strideBackup, 0, stride, 0, rank);
1413                System.arraycopy(selectedBackup, 0, selected, 0, rank);
1414                System.arraycopy(startBackup, 0, start, 0, rank);
1415                System.arraycopy(selectedIndexBackup, 0, selectedIndex, 0, 3);
1416            }
1417
1418            return preImage;
1419        }
1420
1421        @Override
1422        public void paint (Graphics g) {
1423            g.setColor(Color.blue);
1424
1425            if (previewImage != null) {
1426                g.drawImage(previewImage, 0, 0, this);
1427            }
1428            else {
1429                g.fillRect(0, 0, x, y);
1430            }
1431
1432            int w = selectedArea.width;
1433            int h = selectedArea.height;
1434            if ((w > 0) && (h > 0)) {
1435                g.setColor(Color.red);
1436                g.drawRect(selectedArea.x, selectedArea.y, w, h);
1437            }
1438        }
1439
1440        @Override
1441        public void mousePressed (MouseEvent e) {
1442            startPosition = e.getPoint();
1443            selectedArea.setBounds(startPosition.x, startPosition.y, 0, 0);
1444        }
1445
1446        @Override
1447        public void mouseClicked (MouseEvent e) {
1448            startPosition = e.getPoint();
1449            selectedArea.setBounds(startPosition.x, startPosition.y, 0, 0);
1450            repaint();
1451        }
1452
1453        @Override
1454        public void mouseDragged (MouseEvent e) {
1455            Point p0 = startPosition;
1456            Point p1 = e.getPoint();
1457
1458            int x0 = Math.max(0, Math.min(p0.x, p1.x));
1459            int y0 = Math.max(0, Math.min(p0.y, p1.y));
1460            int x1 = Math.min(x, Math.max(p0.x, p1.x));
1461            int y1 = Math.min(y, Math.max(p0.y, p1.y));
1462
1463            int w = x1 - x0;
1464            int h = y1 - y0;
1465            selectedArea.setBounds(x0, y0, w, h);
1466
1467            try {
1468                updateSelection(x0, y0, w, h);
1469            }
1470            catch (Exception ex) {
1471            }
1472
1473            repaint();
1474        }
1475
1476        private void updateSelection (int x0, int y0, int w, int h) {
1477            int i0 = 0, i1 = 0;
1478            String selStr;
1479
1480            i0 = (int) (y0 * r);
1481            if (i0 > dims[currentIndex[0]]) {
1482                i0 = (int) dims[currentIndex[0]];
1483            }
1484            startFields[0].setText(String.valueOf(i0));
1485
1486            i1 = (int) ((y0 + h) * r);
1487
1488            if (i1 < i0) {
1489                i1 = i0;
1490            }
1491            endFields[0].setText(String.valueOf(i1));
1492
1493            selStr = String.valueOf((int) (h * r));
1494
1495            if (rank > 1) {
1496                i0 = (int) (x0 * r);
1497                if (i0 > dims[currentIndex[1]]) {
1498                    i0 = (int) dims[currentIndex[1]];
1499                }
1500                startFields[1].setText(String.valueOf(i0));
1501
1502                i1 = (int) ((x0 + w) * r);
1503                if (i1 < i0) {
1504                    i1 = i0;
1505                }
1506                endFields[1].setText(String.valueOf(i1));
1507
1508                selStr += " x " + ((int) (w * r));
1509            }
1510
1511            selLabel.setText(selStr);
1512        }
1513
1514        @Override
1515        public void mouseReleased (MouseEvent e) {
1516        }
1517
1518        @Override
1519        public void mouseEntered (MouseEvent e) {
1520        }
1521
1522        @Override
1523        public void mouseExited (MouseEvent e) {
1524        }
1525
1526        @Override
1527        public void mouseMoved (MouseEvent e) {
1528        }
1529
1530        private void setDimensionSize (int w, int h) {
1531            dimX = w;
1532            dimY = h;
1533            if (dimX > dimY) {
1534                x = NAVIGATOR_SIZE;
1535                r = dimX / (double) x;
1536                y = (int) (dimY / r);
1537            }
1538            else {
1539                y = NAVIGATOR_SIZE;
1540                r = dimY / (double) y;
1541                x = (int) (dimX / r);
1542            }
1543            setPreferredSize(new Dimension(NAVIGATOR_SIZE, NAVIGATOR_SIZE));
1544            selectedArea.setSize(0, 0);
1545            try {
1546                previewImage = createPreviewImage();
1547            }
1548            catch (Exception ex) {
1549            }
1550
1551            repaint();
1552        }
1553    } // private class SubsetNavigator extends JComponent
1554
1555    /**
1556     *
1557     * @return true if display the data as characters; otherwise, display as numbers.
1558     */
1559    public boolean isDisplayTypeChar ( ) {
1560        return charCheckbox.isSelected();
1561    }
1562
1563    /**
1564     * Returns the bitmask.
1565     *
1566     * @return the bitmask to apply
1567     */
1568    public BitSet getBitmask ( ) {
1569        if (bitmask == null)
1570            return null;
1571
1572        if (!extractBitButton.isEnabled())
1573            return null;
1574
1575        // do not use bitmask if it is empty (all bits are zero)
1576        if (bitmask.isEmpty())
1577            return null;
1578
1579        boolean isAllSelected = true;
1580        int size = bitmask.size();
1581        for (int i = 0; i < size; i++)
1582            isAllSelected = (bitmask.get(i) && isAllSelected);
1583
1584        // do not use bitmask if it is full (all bits are one)
1585        if (isAllSelected)
1586            return null;
1587
1588        return bitmask;
1589    }
1590
1591    /**
1592     * Check if it only apply bitmask.
1593     *
1594     * @return true if only applying the bitmask; false otherwise
1595     */
1596    public boolean isApplyBitmaskOnly ( )
1597    {
1598        if (getBitmask() == null)
1599            return false;
1600
1601        return applyBitmaskButton.isSelected();
1602    }
1603
1604    /**
1605     *
1606     * @return true if transpose the data in 2D table; otherwise, do not transpose the data.
1607     */
1608    public boolean isTransposed ( ) {
1609        return (transposeChoice.getSelectedIndex() == 1);
1610    }
1611
1612    /**
1613     * Returns the name of selected dataview
1614     *
1615     * @return the name of the selected DataView
1616     */
1617    public String getDataViewName ( ) {
1618        String viewName = null;
1619
1620        if (isText) {
1621            viewName = (String) choiceTextView.getSelectedItem();
1622        }
1623        else if (isImageDisplay()) {
1624            viewName = (String) choiceImageView.getSelectedItem();
1625        }
1626        else {
1627            viewName = (String) choiceTableView.getSelectedItem();
1628        }
1629
1630        return viewName;
1631    }
1632}