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