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