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 COPYING file, which can be found  *
009 * at the root of the source code distribution tree,                         *
010 * or in https://www.hdfgroup.org/licenses.                                  *
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.dialog;
016
017import java.awt.Image;
018import java.awt.Rectangle;
019import java.awt.Toolkit;
020import java.awt.image.BufferedImage;
021import java.awt.image.ComponentColorModel;
022import java.awt.image.DirectColorModel;
023import java.awt.image.FilteredImageSource;
024import java.awt.image.ImageFilter;
025import java.awt.image.ImageProducer;
026import java.awt.image.IndexColorModel;
027import java.awt.image.WritableRaster;
028import java.util.BitSet;
029import java.util.StringTokenizer;
030import java.util.Vector;
031
032import hdf.object.CompoundDS;
033import hdf.object.DataFormat;
034import hdf.object.Dataset;
035import hdf.object.Datatype;
036import hdf.object.FileFormat;
037import hdf.object.HObject;
038import hdf.object.ScalarDS;
039import hdf.view.HDFView;
040import hdf.view.ImageView.DefaultImageView;
041import hdf.view.ImageView.DefaultImageView.FlipFilter;
042import hdf.view.ImageView.DefaultImageView.Rotate90Filter;
043import hdf.view.Tools;
044import hdf.view.ViewProperties;
045
046import org.slf4j.Logger;
047import org.slf4j.LoggerFactory;
048
049import org.eclipse.swt.SWT;
050import org.eclipse.swt.events.DisposeEvent;
051import org.eclipse.swt.events.DisposeListener;
052import org.eclipse.swt.events.MouseEvent;
053import org.eclipse.swt.events.MouseListener;
054import org.eclipse.swt.events.MouseMoveListener;
055import org.eclipse.swt.events.PaintEvent;
056import org.eclipse.swt.events.PaintListener;
057import org.eclipse.swt.events.SelectionAdapter;
058import org.eclipse.swt.events.SelectionEvent;
059import org.eclipse.swt.graphics.Font;
060import org.eclipse.swt.graphics.GC;
061import org.eclipse.swt.graphics.ImageData;
062import org.eclipse.swt.graphics.PaletteData;
063import org.eclipse.swt.graphics.Point;
064import org.eclipse.swt.graphics.RGB;
065import org.eclipse.swt.layout.GridData;
066import org.eclipse.swt.layout.GridLayout;
067import org.eclipse.swt.widgets.Button;
068import org.eclipse.swt.widgets.Canvas;
069import org.eclipse.swt.widgets.Combo;
070import org.eclipse.swt.widgets.Composite;
071import org.eclipse.swt.widgets.Dialog;
072import org.eclipse.swt.widgets.Display;
073import org.eclipse.swt.widgets.Event;
074import org.eclipse.swt.widgets.Label;
075import org.eclipse.swt.widgets.List;
076import org.eclipse.swt.widgets.Listener;
077import org.eclipse.swt.widgets.Shell;
078import org.eclipse.swt.widgets.Text;
079
080/**
081 * DataOptionDialog is an dialog window used to select display options. Display options include
082 * selection of subset, display type (image, text, or spreadsheet).
083 *
084 * @author Jordan T. Henderson
085 * @version 2.4 3/26/2016
086 */
087public class DataOptionDialog extends Dialog {
088
089    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DataOptionDialog.class);
090
091    private Shell shell;
092
093    private Font curFont;
094
095    /** the rank of the dataset/image */
096    private int rank;
097
098    /** the starting point of selected subset */
099    private long[] start;
100
101    /** the sizes of all dimensions */
102    private long[] dims;
103
104    /** the selected sizes of all dimensions */
105    private long[] selected;
106
107    /** the stride */
108    private long[] stride;
109
110    /** the indices of the selected dimensions. */
111    private int[] selectedIndex;
112    private int[] currentIndex;
113
114    private BitSet bitmask;
115
116    private Button spreadsheetButton;
117    private Button imageButton;
118    private Button base1Button;
119    private Button base0Button;
120    private Button charCheckbox;
121    private Button bitmaskHelp;
122    private Button applyBitmaskButton;
123    private Button extractBitButton;
124    private Button[] bitmaskButtons;
125
126    private Combo choiceTableView;
127    private Combo choiceImageView;
128    private Combo choicePalette;
129    private Combo transposeChoice;
130    private Combo[] choices;
131
132    private boolean isSelectionCancelled;
133    private boolean isTrueColorImage;
134    private boolean isH5;
135    private boolean isImageDisplay     = false;
136    private boolean isDisplayTypeChar  = false;
137    private boolean isTransposed       = false;
138    private boolean isIndexBase1       = false;
139    private boolean isApplyBitmaskOnly = false;
140
141    private String dataViewName;
142
143    private Label[] maxLabels;
144
145    private Text[] startFields;
146    private Text[] endFields;
147    private Text[] strideFields;
148
149    private Text dataRangeField;
150    private Text fillValueField;
151
152    private List fieldList;
153
154    private PreviewNavigator navigator;
155
156    private int numberOfPalettes;
157
158    /** the selected dataset/image */
159    private DataFormat dataObject;
160
161    /**
162     * Constructs a DataOptionDialog with the given HDFView.
163     *
164     * @param parent
165     *            the parent of this dialog
166     * @param dataObject
167     *            the data object associated with this dialog
168     */
169    public DataOptionDialog(Shell parent, DataFormat dataObject)
170    {
171        super(parent, SWT.APPLICATION_MODAL);
172
173        if (dataObject == null)
174            return;
175
176        this.dataObject = dataObject;
177
178        try {
179            curFont = new Font(Display.getCurrent(), ViewProperties.getFontType(),
180                               ViewProperties.getFontSize(), SWT.NORMAL);
181        }
182        catch (Exception ex) {
183            curFont = null;
184        }
185
186        isSelectionCancelled = true;
187        isTrueColorImage     = false;
188        bitmask              = null;
189        numberOfPalettes     = 1;
190
191        if (!dataObject.isInited())
192            dataObject.init();
193
194        if (isH5 && (dataObject instanceof ScalarDS))
195            numberOfPalettes = ((ScalarDS)dataObject).getNumberOfPalettes();
196
197        rank          = dataObject.getRank();
198        dims          = dataObject.getDims();
199        selected      = dataObject.getSelectedDims();
200        start         = dataObject.getStartDims();
201        selectedIndex = dataObject.getSelectedIndex();
202        stride        = dataObject.getStride();
203        currentIndex  = new int[Math.min(3, rank)];
204
205        maxLabels    = new Label[3];
206        startFields  = new Text[3];
207        endFields    = new Text[3];
208        strideFields = new Text[3];
209        choices      = new Combo[3];
210
211        isH5 = ((HObject)dataObject)
212                   .getFileFormat()
213                   .isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5));
214    }
215
216    /**
217     * Open the DataOptionDialoDialog used to select display options for an object.
218     */
219    public void open()
220    {
221        Shell parent = getParent();
222        shell        = new Shell(parent, SWT.SHELL_TRIM | SWT.APPLICATION_MODAL);
223        shell.setFont(curFont);
224        shell.setText("Dataset Selection - " + ((HObject)dataObject).getPath() +
225                      ((HObject)dataObject).getName());
226        shell.setImages(ViewProperties.getHdfIcons());
227        shell.setLayout(new GridLayout(1, true));
228
229        if (dataObject instanceof ScalarDS) {
230            createScalarDSContents();
231        }
232        else if (dataObject instanceof CompoundDS) {
233            createCompoundDSContents();
234        }
235
236        // Create Ok/Cancel button region
237        Composite buttonComposite = new Composite(shell, SWT.NONE);
238        buttonComposite.setLayout(new GridLayout(2, true));
239        buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
240
241        Button okButton = new Button(buttonComposite, SWT.PUSH);
242        okButton.setFont(curFont);
243        okButton.setText("   &OK   ");
244        okButton.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
245        okButton.addSelectionListener(new SelectionAdapter() {
246            @Override
247            public void widgetSelected(SelectionEvent e)
248            {
249                // set palette for image view
250                if (imageButton != null) {
251                    if ((dataObject instanceof ScalarDS) && imageButton.getSelection()) {
252                        setPalette();
253                    }
254                }
255
256                isSelectionCancelled = !setSelection();
257
258                if (isSelectionCancelled) {
259                    return;
260                }
261
262                if (imageButton != null) {
263                    if (dataObject instanceof ScalarDS) {
264                        ((ScalarDS)dataObject).setIsImageDisplay(imageButton.getSelection());
265                    }
266                }
267
268                shell.notifyListeners(SWT.Close, null);
269
270                shell.dispose();
271            }
272        });
273
274        Button cancelButton = new Button(buttonComposite, SWT.PUSH);
275        cancelButton.setFont(curFont);
276        cancelButton.setText(" &Cancel ");
277        cancelButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, true, false));
278        cancelButton.addSelectionListener(new SelectionAdapter() {
279            @Override
280            public void widgetSelected(SelectionEvent e)
281            {
282                shell.notifyListeners(SWT.Close, null);
283
284                shell.dispose();
285            }
286        });
287
288        shell.pack();
289
290        init();
291
292        shell.setMinimumSize(shell.computeSize(SWT.DEFAULT, SWT.DEFAULT));
293
294        org.eclipse.swt.graphics.Rectangle parentBounds = parent.getBounds();
295        Point shellSize                                 = shell.getSize();
296        shell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2),
297                          (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2));
298
299        shell.addListener(SWT.Close, new Listener() {
300            @Override
301            public void handleEvent(Event e)
302            {
303                if (imageButton == null) {
304                    isImageDisplay = false;
305                }
306                else {
307                    isImageDisplay = imageButton.getSelection();
308                }
309
310                if (charCheckbox == null) {
311                    isDisplayTypeChar = false;
312                }
313                else {
314                    isDisplayTypeChar = charCheckbox.getSelection();
315                }
316
317                if (transposeChoice == null) {
318                    isTransposed = false;
319                }
320                else {
321                    isTransposed = transposeChoice.isEnabled() && transposeChoice.getSelectionIndex() == 0;
322                }
323
324                if (base1Button == null) {
325                    isIndexBase1 = false;
326                }
327                else {
328                    isIndexBase1 = base1Button.getSelection();
329                }
330
331                if (applyBitmaskButton == null) {
332                    isApplyBitmaskOnly = false;
333                }
334                else {
335                    isApplyBitmaskOnly = applyBitmaskButton.getSelection();
336                }
337
338                if (isImageDisplay()) {
339                    dataViewName = choiceImageView.getItem(choiceImageView.getSelectionIndex());
340                }
341                else {
342                    dataViewName = choiceTableView.getItem(choiceTableView.getSelectionIndex());
343                }
344            }
345        });
346
347        shell.addDisposeListener(new DisposeListener() {
348            @Override
349            public void widgetDisposed(DisposeEvent e)
350            {
351                if (curFont != null)
352                    curFont.dispose();
353            }
354        });
355
356        shell.open();
357
358        // Prevent SWT from selecting TableView button by
359        // default if dataset is an image
360        if (dataObject instanceof ScalarDS) {
361            if (((ScalarDS)dataObject).isImageDisplay()) {
362                spreadsheetButton.setSelection(false);
363            }
364        }
365
366        Display display = parent.getDisplay();
367        while (!shell.isDisposed()) {
368            if (!display.readAndDispatch())
369                display.sleep();
370        }
371    }
372
373    /**
374     * Set the initial state of all the variables
375     */
376    private void init()
377    {
378        // set the imagebutton state
379        boolean isImage = false;
380
381        if (dataObject instanceof ScalarDS) {
382            if (!dataObject.getDatatype().isText()) {
383                ScalarDS sd      = (ScalarDS)dataObject;
384                isImage          = sd.isImageDisplay();
385                isTrueColorImage = sd.isTrueColor();
386                // compound datasets don't have data range or fill values
387                // (JAVA-1825)
388                dataRangeField.setEnabled(isImage);
389                fillValueField.setEnabled(isImage);
390            }
391        }
392
393        if (choiceTableView != null) {
394            choiceTableView.setEnabled(!isImage);
395        }
396
397        if (choiceImageView != null) {
398            choiceImageView.setEnabled(isImage);
399        }
400
401        if (imageButton != null) {
402            imageButton.setSelection(isImage);
403        }
404
405        if (choicePalette != null) {
406            choicePalette.setEnabled(isImage && !isTrueColorImage);
407        }
408
409        int n       = Math.min(3, rank);
410        long endIdx = 0;
411        for (int i = 0; i < n; i++) {
412            choices[i].setEnabled(true);
413            startFields[i].setEnabled(true);
414            endFields[i].setEnabled(true);
415            strideFields[i].setEnabled(true);
416            maxLabels[i].setEnabled(true);
417
418            int idx = selectedIndex[i];
419            endIdx  = start[idx] + selected[idx] * stride[idx];
420            if (endIdx >= dims[idx]) {
421                endIdx = dims[idx];
422            }
423
424            choices[i].select(idx);
425            maxLabels[i].setText(String.valueOf(dims[idx]));
426            startFields[i].setText(String.valueOf(start[idx]));
427            endFields[i].setText(String.valueOf(endIdx - 1));
428
429            if (!isH5 && (dataObject instanceof CompoundDS)) {
430                strideFields[i].setEnabled(false);
431            }
432            else {
433                strideFields[i].setText(String.valueOf(stride[idx]));
434            }
435        }
436
437        if (rank > 1) {
438            transposeChoice.setEnabled((choices[0].getSelectionIndex() > choices[1].getSelectionIndex()));
439
440            if (rank > 2) {
441                endFields[2].setEnabled(false);
442                strideFields[2].setEnabled(false);
443
444                if (isTrueColorImage && imageButton != null) {
445                    if (imageButton.getSelection()) {
446                        choices[0].setEnabled(false);
447                        choices[1].setEnabled(false);
448                        choices[2].setEnabled(false);
449                        startFields[2].setEnabled(false);
450                        startFields[2].setText("0");
451                        endFields[2].setEnabled(false);
452                        endFields[2].setText("0");
453                    }
454                }
455                else {
456                    endFields[2].setText(startFields[2].getText());
457                }
458            }
459        }
460
461        for (int i = 0; i < n; i++) {
462            currentIndex[i] = choices[i].getSelectionIndex();
463        }
464
465        // reset show char button
466        Datatype dtype = dataObject.getDatatype();
467        if (dtype.isChar() || dtype.isInteger()) {
468            int tsize = (int)dtype.getDatatypeSize();
469
470            if (charCheckbox != null) {
471                charCheckbox.setEnabled((tsize == 1) && spreadsheetButton.getSelection());
472            }
473
474            if (extractBitButton != null) {
475                extractBitButton.setEnabled(tsize <= 8);
476            }
477
478            if (applyBitmaskButton != null) {
479                applyBitmaskButton.setEnabled(tsize <= 8);
480            }
481        }
482        else {
483            if (charCheckbox != null) {
484                charCheckbox.setEnabled(false);
485                charCheckbox.setSelection(false);
486            }
487
488            if (extractBitButton != null) {
489                extractBitButton.setEnabled(false);
490            }
491
492            if (applyBitmaskButton != null) {
493                applyBitmaskButton.setEnabled(false);
494            }
495        }
496    }
497
498    private void setPalette()
499    {
500        if (!(dataObject instanceof ScalarDS)) {
501            return;
502        }
503
504        byte[][] pal  = null;
505        int palChoice = choicePalette.getSelectionIndex();
506
507        if (palChoice == 0) {
508            return; /* using default palette */
509        }
510
511        if (palChoice == numberOfPalettes + 1) {
512            pal = Tools.createGrayPalette();
513        }
514        else if (palChoice == numberOfPalettes + 2) {
515            pal = Tools.createReverseGrayPalette();
516        }
517        else if (palChoice == numberOfPalettes + 3) {
518            pal = Tools.createGrayWavePalette();
519        }
520        else if (palChoice == numberOfPalettes + 4) {
521            pal = Tools.createRainbowPalette();
522        }
523        else if (palChoice == numberOfPalettes + 5) {
524            pal = Tools.createNaturePalette();
525        }
526        else if (palChoice == numberOfPalettes + 6) {
527            pal = Tools.createWavePalette();
528        }
529        else if ((palChoice > 0) && (palChoice <= numberOfPalettes)) {
530            // multiple palettes attached
531            pal = ((ScalarDS)dataObject).readPalette(palChoice - 1);
532        }
533
534        ((ScalarDS)dataObject).setPalette(pal);
535    }
536
537    private boolean setSelection()
538    {
539        long[] n0      = {0, 0, 0}; // start
540        long[] n1      = {0, 0, 0}; // end
541        long[] n2      = {1, 1, 1}; // stride
542        int[] sIndex   = {0, 1, 2};
543        boolean retVal = true;
544
545        int n = Math.min(3, rank);
546        for (int i = 0; i < n; i++) {
547            sIndex[i] = choices[i].getSelectionIndex();
548
549            try {
550                n0[i] = Long.parseLong(startFields[i].getText());
551                if (i < 2) {
552                    n1[i] = Long.parseLong(endFields[i].getText());
553                    n2[i] = Long.parseLong(strideFields[i].getText());
554                }
555            }
556            catch (NumberFormatException ex) {
557                shell.getDisplay().beep();
558                Tools.showError(shell, "Set", ex.getMessage());
559                return false;
560            }
561
562            // silently correct errors
563            if (n0[i] < 0) {
564                n0[i] = 0; // start
565            }
566            if (n0[i] >= dims[sIndex[i]]) {
567                n0[i] = dims[sIndex[i]] - 1;
568            }
569            if (n1[i] < 0) {
570                n1[i] = 0; // end
571            }
572            if (n1[i] >= dims[sIndex[i]]) {
573                n1[i] = dims[sIndex[i]] - 1;
574            }
575            if (n0[i] > n1[i]) {
576                n1[i] = n0[i]; // end <= start
577            }
578            if (n2[i] > dims[sIndex[i]]) {
579                n2[i] = dims[sIndex[i]];
580            }
581            if (n2[i] <= 0) {
582                n2[i] = 1; // stride cannot be zero
583            }
584        } //  (int i=0; i<n; i++)
585
586        if (dataObject instanceof CompoundDS) {
587            CompoundDS d               = (CompoundDS)dataObject;
588            int[] selectedFieldIndices = fieldList.getSelectionIndices();
589            if ((selectedFieldIndices == null) || (selectedFieldIndices.length < 1)) {
590                shell.getDisplay().beep();
591                Tools.showError(shell, "Set", "No member/field is selected.");
592                return false;
593            }
594
595            d.setAllMemberSelection(false); // deselect all members
596            for (int i = 0; i < selectedFieldIndices.length; i++) {
597                d.selectMember(selectedFieldIndices[i]);
598            }
599        }
600        else {
601            ScalarDS ds = (ScalarDS)dataObject;
602
603            if (!ds.getDatatype().isText()) {
604                StringTokenizer st = new StringTokenizer(dataRangeField.getText(), ",");
605                if (st.countTokens() == 2) {
606                    double min = 0, max = 0;
607                    try {
608                        min = Double.valueOf(st.nextToken());
609                        max = Double.valueOf(st.nextToken());
610                    }
611                    catch (Exception ex) {
612                    }
613                    if (max > min)
614                        ds.setImageDataRange(min, max);
615                }
616                st = new StringTokenizer(fillValueField.getText(), ",");
617                while (st.hasMoreTokens()) {
618                    double x = 0;
619                    try {
620                        x = Double.valueOf(st.nextToken());
621                        ds.addFilteredImageValue(x);
622                    }
623                    catch (Exception ex) {
624                    }
625                }
626            }
627        }
628
629        // reset selected size
630        for (int i = 0; i < rank; i++) {
631            selected[i] = 1;
632            stride[i]   = 1;
633        }
634
635        // find no error, set selection the the dataset object
636        for (int i = 0; i < n; i++) {
637            long selectedSize = ((n1[i] - n0[i]) / n2[i]) + 1;
638
639            /*
640             * Since Java does not allow array indices to be larger than int type, check the
641             * given value to see if it is within the valid range of a Java int.
642             */
643            if (!Tools.checkValidJavaArrayIndex(selectedSize)) {
644                shell.getDisplay().beep();
645                Tools.showError(shell, "Set", "Subset selection too large to display.");
646                return false;
647            }
648
649            selectedIndex[i]           = sIndex[i];
650            start[selectedIndex[i]]    = n0[i];
651            selected[selectedIndex[i]] = (int)selectedSize;
652            stride[selectedIndex[i]]   = n2[i];
653        }
654
655        if ((rank > 2) && isTrueColorImage && imageButton.getSelection()) {
656            start[selectedIndex[2]]    = 0;
657            selected[selectedIndex[2]] = 3;
658        }
659
660        // clear the old data
661        dataObject.clearData();
662
663        setBitmask();
664
665        return retVal;
666    }
667
668    private void setBitmask()
669    {
670        boolean isAll     = true;
671        boolean isNothing = true;
672
673        if (bitmaskButtons == null) {
674            bitmask = null;
675            return;
676        }
677
678        if (!(applyBitmaskButton.getSelection() || extractBitButton.getSelection())) {
679            bitmask = null;
680            return;
681        }
682
683        int len = bitmaskButtons.length;
684        for (int i = 0; i < len; i++) {
685            isAll     = (isAll && bitmaskButtons[i].getSelection());
686            isNothing = (isNothing && !bitmaskButtons[i].getSelection());
687        }
688
689        if (isAll || isNothing) {
690            bitmask = null;
691            return;
692        }
693
694        if (bitmask == null)
695            bitmask = new BitSet(len);
696
697        for (int i = 0; i < len; i++) {
698            /* Bitmask buttons are indexed from highest to lowest */
699            bitmask.set(i, bitmaskButtons[len - i - 1].getSelection());
700        }
701    }
702
703    /** @return true if the display option is image. */
704    public boolean isImageDisplay() { return isImageDisplay; }
705
706    /** @return true if the index starts with 0. */
707    public boolean isIndexBase1() { return isIndexBase1; }
708
709    /**
710     * @return the bitmask.
711     */
712    public BitSet getBitmask()
713    {
714        if (bitmask == null)
715            return null;
716
717        // do not use bitmask if it is empty (all bits are zero)
718        if (bitmask.isEmpty())
719            return null;
720
721        boolean isAllSelected = true;
722        int size              = bitmask.size();
723        for (int i = 0; i < size; i++)
724            isAllSelected = (bitmask.get(i) && isAllSelected);
725
726        // do not use bitmask if it is full (all bits are one)
727        if (isAllSelected)
728            return null;
729
730        return bitmask;
731    }
732
733    /** @return the name of the selected dataview */
734    public String getDataViewName() { return dataViewName; }
735
736    /**
737     *
738     * @return true if display the data as characters; otherwise, display as numbers.
739     */
740    public boolean isDisplayTypeChar() { return isDisplayTypeChar; }
741
742    /**
743     * @return if it only apply bitmask.
744     */
745    public boolean isApplyBitmaskOnly() { return isApplyBitmaskOnly; }
746
747    /**
748     *
749     * @return true if transpose the data in 2D table; otherwise, do not transpose the data.
750     */
751    public boolean isTransposed() { return isTransposed; }
752
753    /** @return true if the data selection is cancelled. */
754    public boolean isCancelled() { return isSelectionCancelled; }
755
756    private void createScalarDSContents()
757    {
758        // Create display type region
759        org.eclipse.swt.widgets.Group displayAsGroup = new org.eclipse.swt.widgets.Group(shell, SWT.NONE);
760        displayAsGroup.setFont(curFont);
761        displayAsGroup.setText("Display As");
762        displayAsGroup.setLayout(new GridLayout(1, true));
763        displayAsGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
764
765        Composite spreadsheetComposite = new Composite(displayAsGroup, SWT.BORDER);
766        spreadsheetComposite.setLayout(new GridLayout(2, false));
767        spreadsheetComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
768
769        spreadsheetButton = new Button(spreadsheetComposite, SWT.RADIO);
770        spreadsheetButton.setFont(curFont);
771        spreadsheetButton.setText("&Spreadsheet");
772        spreadsheetButton.setSelection(true);
773        spreadsheetButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
774        spreadsheetButton.addSelectionListener(new SelectionAdapter() {
775            @Override
776            public void widgetSelected(SelectionEvent e)
777            {
778                imageButton.setSelection(!spreadsheetButton.getSelection());
779                choicePalette.setEnabled(false);
780                choiceImageView.setEnabled(false);
781                choiceTableView.setEnabled(true);
782                dataRangeField.setEnabled(false);
783                fillValueField.setEnabled(false);
784                Datatype dtype = dataObject.getDatatype();
785                charCheckbox.setEnabled((dtype.isChar() || dtype.isInteger()) &&
786                                        (dtype.getDatatypeSize() == 1));
787            }
788        });
789
790        charCheckbox = new Button(spreadsheetComposite, SWT.CHECK);
791        charCheckbox.setFont(curFont);
792        charCheckbox.setText("Show As &Char");
793        charCheckbox.setSelection(false);
794        charCheckbox.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, false, false));
795
796        if (dataObject.getDatatype().isChar() ||
797            (dataObject.getDatatype().isInteger() && dataObject.getDatatype().getDatatypeSize() == 1)) {
798            charCheckbox.setEnabled(false);
799        }
800
801        Label label = new Label(spreadsheetComposite, SWT.RIGHT);
802        label.setFont(curFont);
803        label.setText("TableView: ");
804
805        choiceTableView = new Combo(spreadsheetComposite, SWT.SINGLE | SWT.DROP_DOWN | SWT.READ_ONLY);
806        choiceTableView.setFont(curFont);
807        choiceTableView.setItems(HDFView.getListOfTableViews().toArray(new String[0]));
808        choiceTableView.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
809        choiceTableView.select(0);
810
811        Composite imageComposite = new Composite(displayAsGroup, SWT.BORDER);
812        imageComposite.setLayout(new GridLayout(4, false));
813        imageComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
814
815        imageButton = new Button(imageComposite, SWT.RADIO);
816        imageButton.setFont(curFont);
817        imageButton.setText("&Image");
818        imageButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
819        imageButton.addSelectionListener(new SelectionAdapter() {
820            @Override
821            public void widgetSelected(SelectionEvent e)
822            {
823                spreadsheetButton.setSelection(!imageButton.getSelection());
824                choicePalette.setEnabled(!isTrueColorImage);
825                dataRangeField.setEnabled(true);
826                fillValueField.setEnabled(true);
827                choiceImageView.setEnabled(true);
828                choiceTableView.setEnabled(false);
829                charCheckbox.setSelection(false);
830                charCheckbox.setEnabled(false);
831            }
832        });
833
834        choicePalette = new Combo(imageComposite, SWT.SINGLE | SWT.DROP_DOWN | SWT.READ_ONLY);
835        choicePalette.setFont(curFont);
836        choicePalette.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
837
838        choicePalette.add("Select palette");
839
840        if (dataObject instanceof ScalarDS) {
841            String paletteName = ((ScalarDS)dataObject).getPaletteName(0);
842            if (paletteName == null) {
843                paletteName = "Default";
844            }
845            choicePalette.add(paletteName);
846            for (int i = 2; i <= numberOfPalettes; i++) {
847                paletteName = ((ScalarDS)dataObject).getPaletteName(i - 1);
848                choicePalette.add(paletteName);
849            }
850        }
851        choicePalette.add("Gray");
852        choicePalette.add("ReverseGray");
853        choicePalette.add("GrayWave");
854        choicePalette.add("Rainbow");
855        choicePalette.add("Nature");
856        choicePalette.add("Wave");
857
858        choicePalette.select(0);
859
860        label = new Label(imageComposite, SWT.RIGHT);
861        label.setFont(curFont);
862        label.setText("Valid Range: ");
863
864        dataRangeField = new Text(imageComposite, SWT.SINGLE | SWT.BORDER);
865        dataRangeField.setFont(curFont);
866        dataRangeField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
867
868        String minmaxStr = "min, max";
869
870        double[] minmax = ((ScalarDS)dataObject).getImageDataRange();
871        if (minmax != null) {
872            if (dataObject.getDatatype().isFloat())
873                minmaxStr = minmax[0] + "," + minmax[1];
874            else
875                minmaxStr = ((long)minmax[0]) + "," + ((long)minmax[1]);
876        }
877
878        dataRangeField.setText(minmaxStr);
879
880        label = new Label(imageComposite, SWT.RIGHT);
881        label.setFont(curFont);
882        label.setText("ImageView: ");
883
884        choiceImageView = new Combo(imageComposite, SWT.SINGLE | SWT.DROP_DOWN | SWT.READ_ONLY);
885        choiceImageView.setFont(curFont);
886        choiceImageView.setItems(HDFView.getListOfImageViews().toArray(new String[0]));
887        choiceImageView.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
888        choiceImageView.select(0);
889
890        label = new Label(imageComposite, SWT.RIGHT);
891        label.setFont(curFont);
892        label.setText("Invalid Values: ");
893
894        fillValueField = new Text(imageComposite, SWT.SINGLE | SWT.BORDER);
895        fillValueField.setFont(curFont);
896        fillValueField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
897
898        String fillStr = "val1, val2, ...";
899
900        java.util.List<Number> fillValue = ((ScalarDS)dataObject).getFilteredImageValues();
901        int n                            = fillValue.size();
902        if (n > 0) {
903            fillStr = fillValue.get(0).toString();
904            for (int i = 1; i < n; i++) {
905                fillStr += ", " + fillValue.get(i);
906            }
907        }
908
909        fillValueField.setText(fillStr);
910
911        // Create Index Base region
912        org.eclipse.swt.widgets.Group indexBaseGroup = new org.eclipse.swt.widgets.Group(shell, SWT.NONE);
913        indexBaseGroup.setFont(curFont);
914        indexBaseGroup.setText("Index Base");
915        indexBaseGroup.setLayout(new GridLayout(2, true));
916        indexBaseGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
917
918        base0Button = new Button(indexBaseGroup, SWT.RADIO);
919        base0Button.setFont(curFont);
920        base0Button.setText("0-based");
921        base0Button.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, true, false));
922
923        base1Button = new Button(indexBaseGroup, SWT.RADIO);
924        base1Button.setFont(curFont);
925        base1Button.setText("1-based");
926        base1Button.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, true, false));
927
928        if (ViewProperties.isIndexBase1()) {
929            base0Button.setSelection(false);
930            base1Button.setSelection(true);
931        }
932        else {
933            base0Button.setSelection(true);
934            base1Button.setSelection(false);
935        }
936
937        // Create Bitmask region
938        org.eclipse.swt.widgets.Group bitmaskGroup = new org.eclipse.swt.widgets.Group(shell, SWT.NONE);
939        bitmaskGroup.setFont(curFont);
940        bitmaskGroup.setText("Bitmask");
941        bitmaskGroup.setLayout(new GridLayout(2, false));
942        bitmaskGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
943
944        extractBitButton = new Button(bitmaskGroup, SWT.CHECK);
945        extractBitButton.setFont(curFont);
946        extractBitButton.setText("Show &Value of Selected Bits");
947        extractBitButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, false, false));
948        extractBitButton.setSelection(false);
949        extractBitButton.addSelectionListener(new SelectionAdapter() {
950            @Override
951            public void widgetSelected(SelectionEvent e)
952            {
953                boolean selected = extractBitButton.getSelection();
954
955                if (selected) {
956                    if (applyBitmaskButton.getSelection()) {
957                        applyBitmaskButton.setSelection(false);
958                    }
959
960                    if (!bitmaskButtons[0].getEnabled()) {
961                        for (int i = 0; i < bitmaskButtons.length; i++) {
962                            bitmaskButtons[i].setEnabled(true);
963                        }
964                    }
965
966                    int n = 0;
967
968                    if (bitmaskButtons[0].getSelection())
969                        n = 1;
970
971                    for (int i = 1; i < bitmaskButtons.length; i++) {
972                        if (bitmaskButtons[i].getSelection() && !bitmaskButtons[i - 1].getSelection()) {
973                            n++;
974                        }
975                    }
976
977                    if (n > 1) {
978                        extractBitButton.setSelection(false);
979                        applyBitmaskButton.setSelection(true);
980
981                        Tools.showError(
982                            shell, "Select",
983                            "Selecting non-adjacent bits is only allowed \nfor the \"Apply Bitmask\" option.");
984                        return;
985                    }
986                }
987                else {
988                    for (int i = 0; i < bitmaskButtons.length; i++) {
989                        bitmaskButtons[i].setEnabled(false);
990                    }
991                }
992            }
993        });
994
995        bitmaskHelp = new Button(bitmaskGroup, SWT.PUSH);
996        bitmaskHelp.setImage(ViewProperties.getHelpIcon());
997        bitmaskHelp.setToolTipText("Help on how to set bitmask");
998        bitmaskHelp.setLayoutData(new GridData(SWT.END, SWT.FILL, false, false));
999        bitmaskHelp.setEnabled(false);
1000        bitmaskHelp.addSelectionListener(new SelectionAdapter() {
1001            @Override
1002            public void widgetSelected(SelectionEvent e)
1003            {
1004                String msg = ""
1005                             + "\"Apply Bitmask\" applies bitwise \"AND\" to the original data.\n"
1006                             + "For example, bits 2, 3, and 4 are selected for the bitmask\n"
1007                             + "         10010101 (data)\n"
1008                             + "AND 00011100 (mask)  \n"
1009                             + "  =     00010100 (result) ==> the decimal value is 20. \n"
1010                             + "\n"
1011                             + "\"Extract Bit(s)\" removes all the bits from the result above where\n"
1012                             + "their corresponding bits in the bitmask are 0. \nFor the same example above, "
1013                             + "the result is \n101 ==> the decimal value is 5.\n\n";
1014
1015                Tools.showInformation(shell, "Help", msg);
1016            }
1017        });
1018
1019        applyBitmaskButton = new Button(bitmaskGroup, SWT.CHECK);
1020        applyBitmaskButton.setFont(curFont);
1021        applyBitmaskButton.setText("&Apply Bitmask");
1022        applyBitmaskButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, false, false));
1023        applyBitmaskButton.setSelection(false);
1024        applyBitmaskButton.addSelectionListener(new SelectionAdapter() {
1025            @Override
1026            public void widgetSelected(SelectionEvent e)
1027            {
1028                if (extractBitButton.getSelection()) {
1029                    extractBitButton.setSelection(false);
1030                }
1031                else if (!applyBitmaskButton.getSelection()) {
1032                    for (int i = 0; i < bitmaskButtons.length; i++) {
1033                        bitmaskButtons[i].setEnabled(false);
1034                    }
1035                }
1036                else {
1037                    if (!bitmaskButtons[0].getEnabled()) {
1038                        for (int i = 0; i < bitmaskButtons.length; i++) {
1039                            bitmaskButtons[i].setEnabled(true);
1040                        }
1041                    }
1042                }
1043            }
1044        });
1045
1046        new Label(bitmaskGroup, SWT.RIGHT).setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
1047
1048        Composite buttonComposite = new Composite(bitmaskGroup, SWT.NO_RADIO_GROUP);
1049        buttonComposite.setLayout(new GridLayout(16, true));
1050        buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
1051
1052        int tsize;
1053
1054        if (dataObject.getDatatype().isArray()) {
1055            Datatype baseType = dataObject.getDatatype().getDatatypeBase();
1056
1057            while (baseType.isArray()) {
1058                baseType = baseType.getDatatypeBase();
1059            }
1060
1061            tsize = (int)baseType.getDatatypeSize();
1062        }
1063        else {
1064            tsize = (int)dataObject.getDatatype().getDatatypeSize();
1065        }
1066
1067        bitmaskButtons =
1068            (tsize >= 0 && !dataObject.getDatatype().isText()) ? new Button[8 * tsize] : new Button[0];
1069
1070        for (int i = 0; i < bitmaskButtons.length; i++) {
1071            bitmaskButtons[i] = new Button(buttonComposite, SWT.RADIO);
1072            bitmaskButtons[i].setFont(curFont);
1073            bitmaskButtons[i].setText(String.valueOf(bitmaskButtons.length - i - 1));
1074            bitmaskButtons[i].setEnabled(false);
1075            bitmaskButtons[i].addSelectionListener(new SelectionAdapter() {
1076                @Override
1077                public void widgetSelected(SelectionEvent e)
1078                {
1079                    if (extractBitButton.getSelection()) {
1080                        Button source = (Button)e.widget;
1081
1082                        // Don't allow non-adjacent selection of bits when extracting bits
1083                        int n = 0;
1084
1085                        if (bitmaskButtons[0].getSelection())
1086                            n = 1;
1087
1088                        for (int i = 1; i < bitmaskButtons.length; i++) {
1089                            if (bitmaskButtons[i].getSelection() && !bitmaskButtons[i - 1].getSelection()) {
1090                                n++;
1091                            }
1092                        }
1093
1094                        if (n > 1) {
1095                            Tools.showError(
1096                                shell, "Select",
1097                                "Please select contiguous bits \nwhen the \"Show Value of Selected Bits\" option is checked.");
1098
1099                            source.setSelection(false);
1100                            return;
1101                        }
1102                    }
1103                }
1104            });
1105        }
1106
1107        if (dataObject.getDatatype().isChar() || (dataObject.getDatatype().isInteger() && tsize <= 8)) {
1108            extractBitButton.setEnabled(true);
1109            applyBitmaskButton.setEnabled(true);
1110            bitmaskHelp.setEnabled(true);
1111        }
1112
1113        // Create Dimension/Subset selection region
1114        org.eclipse.swt.widgets.Group dimSubGroup = new org.eclipse.swt.widgets.Group(shell, SWT.NONE);
1115        dimSubGroup.setFont(curFont);
1116        dimSubGroup.setText("Dimension and Subset Selection");
1117        dimSubGroup.setLayout(new GridLayout(2, false));
1118        dimSubGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
1119
1120        int h = 1, w = 1;
1121        h = (int)dims[selectedIndex[0]];
1122        if (rank > 1) {
1123            w = (int)dims[selectedIndex[1]];
1124        }
1125
1126        if (rank > 1) {
1127            navigator = new PreviewNavigator(dimSubGroup, SWT.DOUBLE_BUFFERED | SWT.BORDER, w, h);
1128        }
1129        else {
1130            dimSubGroup.setLayout(new GridLayout(1, true));
1131        }
1132
1133        createDimSubSelectionComposite(dimSubGroup);
1134    }
1135
1136    private void createCompoundDSContents()
1137    {
1138        Composite content = new Composite(shell, SWT.NONE);
1139        content.setLayout(new GridLayout(2, false));
1140        content.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
1141
1142        org.eclipse.swt.widgets.Group membersGroup = new org.eclipse.swt.widgets.Group(content, SWT.NONE);
1143        membersGroup.setFont(curFont);
1144        membersGroup.setText("Select Members");
1145        membersGroup.setLayout(new GridLayout(1, true));
1146        membersGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true));
1147
1148        final String[] names = ((CompoundDS)dataObject).getMemberNames();
1149        String[] columnNames = new String[names.length];
1150        for (int i = 0; i < names.length; i++) {
1151            columnNames[i] = new String(names[i]);
1152            columnNames[i] = columnNames[i].replaceAll(CompoundDS.SEPARATOR, "->");
1153        }
1154        fieldList = new List(membersGroup, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL);
1155        fieldList.setFont(curFont);
1156        fieldList.setItems(columnNames);
1157        fieldList.selectAll();
1158
1159        GridData data   = new GridData(SWT.FILL, SWT.FILL, false, true);
1160        data.heightHint = fieldList.getItemHeight() * 10;
1161        data.widthHint  = fieldList.computeSize(SWT.DEFAULT, SWT.DEFAULT).x + 10;
1162        fieldList.setLayoutData(data);
1163
1164        org.eclipse.swt.widgets.Group dimSubGroup = new org.eclipse.swt.widgets.Group(content, SWT.NONE);
1165        dimSubGroup.setFont(curFont);
1166        dimSubGroup.setText("Dimension and Subset Selection");
1167        dimSubGroup.setLayout(new GridLayout());
1168        dimSubGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
1169
1170        createDimSubSelectionComposite(dimSubGroup);
1171
1172        Composite tableViewComposite = new Composite(dimSubGroup, SWT.BORDER);
1173        tableViewComposite.setLayout(new GridLayout(2, false));
1174        tableViewComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
1175
1176        Label label = new Label(tableViewComposite, SWT.RIGHT);
1177        label.setFont(curFont);
1178        label.setText("TableView: ");
1179
1180        choiceTableView = new Combo(tableViewComposite, SWT.SINGLE | SWT.DROP_DOWN | SWT.READ_ONLY);
1181        choiceTableView.setFont(curFont);
1182        choiceTableView.setItems(HDFView.getListOfTableViews().toArray(new String[0]));
1183        choiceTableView.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
1184        choiceTableView.select(0);
1185    }
1186
1187    private void createDimSubSelectionComposite(Composite parent)
1188    {
1189        String[] dimNames = ((Dataset)dataObject).getDimNames();
1190
1191        Composite selectionComposite = new Composite(parent, SWT.BORDER);
1192        selectionComposite.setLayout(new GridLayout(6, true));
1193        selectionComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
1194
1195        new Label(selectionComposite, SWT.RIGHT).setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
1196
1197        if (rank > 1) {
1198            transposeChoice = new Combo(selectionComposite, SWT.SINGLE | SWT.READ_ONLY);
1199            transposeChoice.setFont(curFont);
1200            transposeChoice.setLayoutData(new GridData(SWT.FILL, SWT.END, true, false));
1201
1202            transposeChoice.add("Transpose");
1203            transposeChoice.add("Reshape");
1204
1205            transposeChoice.select(0);
1206        }
1207        else {
1208            new Label(selectionComposite, SWT.RIGHT)
1209                .setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
1210        }
1211
1212        Label label = new Label(selectionComposite, SWT.RIGHT);
1213        label.setFont(curFont);
1214        label.setText("Start: ");
1215        label.setLayoutData(new GridData(SWT.CENTER, SWT.END, true, true));
1216
1217        label = new Label(selectionComposite, SWT.RIGHT);
1218        label.setFont(curFont);
1219        label.setText("End: ");
1220        label.setLayoutData(new GridData(SWT.CENTER, SWT.END, true, true));
1221
1222        label = new Label(selectionComposite, SWT.RIGHT);
1223        label.setFont(curFont);
1224        label.setText("Stride: ");
1225        label.setLayoutData(new GridData(SWT.CENTER, SWT.END, true, true));
1226
1227        label = new Label(selectionComposite, SWT.RIGHT);
1228        label.setFont(curFont);
1229        label.setText("Max Size");
1230        label.setLayoutData(new GridData(SWT.CENTER, SWT.END, true, true));
1231
1232        // Create Height selection row
1233        label = new Label(selectionComposite, SWT.RIGHT);
1234        label.setFont(curFont);
1235        label.setText("Height: ");
1236        label.setLayoutData(new GridData(SWT.END, SWT.CENTER, true, true));
1237
1238        choices[0] = new Combo(selectionComposite, SWT.SINGLE | SWT.READ_ONLY);
1239        choices[0].setFont(curFont);
1240        choices[0].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1241        choices[0].addSelectionListener(new SelectionAdapter() {
1242            @Override
1243            public void widgetSelected(SelectionEvent e)
1244            {
1245                Combo source = (Combo)e.widget;
1246
1247                processComboBoxEvent(source);
1248            }
1249        });
1250
1251        for (int j = 0; j < rank; j++) {
1252            if (dimNames == null) {
1253                choices[0].add("dim " + j);
1254            }
1255            else {
1256                choices[0].add(dimNames[j]);
1257            }
1258        }
1259
1260        choices[0].select(0);
1261
1262        startFields[0] = new Text(selectionComposite, SWT.SINGLE | SWT.BORDER);
1263        startFields[0].setFont(curFont);
1264        startFields[0].setText("0");
1265        startFields[0].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1266
1267        endFields[0] = new Text(selectionComposite, SWT.SINGLE | SWT.BORDER);
1268        endFields[0].setFont(curFont);
1269        endFields[0].setText("0");
1270        endFields[0].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1271
1272        strideFields[0] = new Text(selectionComposite, SWT.SINGLE | SWT.BORDER);
1273        strideFields[0].setFont(curFont);
1274        strideFields[0].setText("1");
1275        strideFields[0].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1276
1277        maxLabels[0] = new Label(selectionComposite, SWT.NONE);
1278        maxLabels[0].setFont(curFont);
1279        maxLabels[0].setText("1");
1280        maxLabels[0].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1281
1282        // Create Width selection row
1283        label = new Label(selectionComposite, SWT.RIGHT);
1284        label.setFont(curFont);
1285        label.setText("Width: ");
1286        label.setLayoutData(new GridData(SWT.END, SWT.CENTER, true, true));
1287
1288        choices[1] = new Combo(selectionComposite, SWT.SINGLE | SWT.READ_ONLY);
1289        choices[1].setFont(curFont);
1290        choices[1].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1291        choices[1].addSelectionListener(new SelectionAdapter() {
1292            @Override
1293            public void widgetSelected(SelectionEvent e)
1294            {
1295                Combo source = (Combo)e.widget;
1296
1297                processComboBoxEvent(source);
1298            }
1299        });
1300
1301        for (int j = 0; j < rank; j++) {
1302            if (dimNames == null) {
1303                choices[1].add("dim " + j);
1304            }
1305            else {
1306                choices[1].add(dimNames[j]);
1307            }
1308        }
1309
1310        choices[1].select(0);
1311
1312        startFields[1] = new Text(selectionComposite, SWT.SINGLE | SWT.BORDER);
1313        startFields[1].setFont(curFont);
1314        startFields[1].setText("0");
1315        startFields[1].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1316
1317        endFields[1] = new Text(selectionComposite, SWT.SINGLE | SWT.BORDER);
1318        endFields[1].setFont(curFont);
1319        endFields[1].setText("0");
1320        endFields[1].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1321
1322        strideFields[1] = new Text(selectionComposite, SWT.SINGLE | SWT.BORDER);
1323        strideFields[1].setFont(curFont);
1324        strideFields[1].setText("1");
1325        strideFields[1].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1326
1327        maxLabels[1] = new Label(selectionComposite, SWT.NONE);
1328        maxLabels[1].setFont(curFont);
1329        maxLabels[1].setText("1");
1330        maxLabels[1].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1331
1332        // Create Depth selection row
1333        label = new Label(selectionComposite, SWT.RIGHT);
1334        label.setFont(curFont);
1335        label.setText("Depth: ");
1336        label.setLayoutData(new GridData(SWT.END, SWT.CENTER, true, true));
1337
1338        choices[2] = new Combo(selectionComposite, SWT.SINGLE | SWT.READ_ONLY);
1339        choices[2].setFont(curFont);
1340        choices[2].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1341        choices[2].addSelectionListener(new SelectionAdapter() {
1342            @Override
1343            public void widgetSelected(SelectionEvent e)
1344            {
1345                Combo source = (Combo)e.widget;
1346
1347                processComboBoxEvent(source);
1348            }
1349        });
1350
1351        for (int j = 0; j < rank; j++) {
1352            if (dimNames == null) {
1353                choices[2].add("dim " + j);
1354            }
1355            else {
1356                choices[2].add(dimNames[j]);
1357            }
1358        }
1359
1360        choices[2].select(0);
1361
1362        startFields[2] = new Text(selectionComposite, SWT.SINGLE | SWT.BORDER);
1363        startFields[2].setFont(curFont);
1364        startFields[2].setText("0");
1365        startFields[2].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1366
1367        endFields[2] = new Text(selectionComposite, SWT.SINGLE | SWT.BORDER);
1368        endFields[2].setFont(curFont);
1369        endFields[2].setText("0");
1370        endFields[2].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1371
1372        strideFields[2] = new Text(selectionComposite, SWT.SINGLE | SWT.BORDER);
1373        strideFields[2].setFont(curFont);
1374        strideFields[2].setText("1");
1375        strideFields[2].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1376
1377        maxLabels[2] = new Label(selectionComposite, SWT.NONE);
1378        maxLabels[2].setFont(curFont);
1379        maxLabels[2].setText("1");
1380        maxLabels[2].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1381
1382        // Create row for Dims and reset button
1383        new Label(selectionComposite, SWT.RIGHT).setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
1384
1385        Button dimsButton = new Button(selectionComposite, SWT.PUSH);
1386        dimsButton.setFont(curFont);
1387        dimsButton.setText("Dims...");
1388        dimsButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
1389        dimsButton.setEnabled((rank > 3));
1390        dimsButton.addSelectionListener(new SelectionAdapter() {
1391            @Override
1392            public void widgetSelected(SelectionEvent e)
1393            {
1394                if (rank < 4) {
1395                    return;
1396                }
1397
1398                int idx                = 0;
1399                Vector<Object> choice4 = new Vector<>(rank);
1400                int[] choice4Index     = new int[rank - 3];
1401                for (int i = 0; i < rank; i++) {
1402                    if ((i != currentIndex[0]) && (i != currentIndex[1]) && (i != currentIndex[2])) {
1403                        choice4.add(choices[0].getItem(i));
1404                        choice4Index[idx++] = i;
1405                    }
1406                }
1407
1408                String msg = "Select slice location for dimension(s):\n\"" + choice4.get(0) + " [0 .. " +
1409                             (dims[choice4Index[0]] - 1) + "]\"";
1410                String initValue = String.valueOf(start[choice4Index[0]]);
1411                int n            = choice4.size();
1412                for (int i = 1; i < n; i++) {
1413                    msg += " x \"" + choice4.get(i) + " [0 .. " + (dims[choice4Index[i]] - 1) + "]\"";
1414                    initValue += " x " + String.valueOf(start[choice4Index[i]]);
1415                }
1416
1417                String result = new InputDialog(shell, shell.getText(), msg, initValue).open();
1418                if ((result == null) || ((result = result.trim()) == null) || (result.length() < 1)) {
1419                    return;
1420                }
1421
1422                StringTokenizer st = new StringTokenizer(result, "x");
1423                if (st.countTokens() < n) {
1424                    Tools.showError(shell, "Select",
1425                                    "Number of dimension(s) is less than " + n + "\n" + result);
1426                    return;
1427                }
1428
1429                long[] start4 = new long[n];
1430                for (int i = 0; i < n; i++) {
1431                    try {
1432                        start4[i] = Long.parseLong(st.nextToken().trim());
1433                    }
1434                    catch (Exception ex) {
1435                        Tools.showError(shell, "Select", ex.getMessage());
1436                        return;
1437                    }
1438
1439                    if ((start4[i] < 0) || (start4[i] >= dims[choice4Index[i]])) {
1440                        Tools.showError(shell, "Select",
1441                                        "Slice location is out of range.\n" + start4[i] +
1442                                            " >= " + dims[choice4Index[i]]);
1443
1444                        return;
1445                    }
1446                }
1447
1448                for (int i = 0; i < n; i++) {
1449                    start[choice4Index[i]] = start4[i];
1450                }
1451            }
1452        });
1453
1454        new Label(selectionComposite, SWT.RIGHT).setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
1455
1456        new Label(selectionComposite, SWT.RIGHT).setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
1457
1458        Button resetButton = new Button(selectionComposite, SWT.PUSH);
1459        resetButton.setFont(curFont);
1460        resetButton.setText("Reset");
1461        resetButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
1462        resetButton.addSelectionListener(new SelectionAdapter() {
1463            @Override
1464            public void widgetSelected(SelectionEvent e)
1465            {
1466                int n = startFields.length;
1467
1468                for (int i = 0; i < n; i++) {
1469                    startFields[i].setText("0");
1470                    strideFields[i].setText("1");
1471                    long l = Long.valueOf(maxLabels[i].getText()) - 1;
1472                    endFields[i].setText(String.valueOf(l));
1473                }
1474            }
1475        });
1476
1477        new Label(selectionComposite, SWT.RIGHT).setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
1478
1479        for (int i = 0; i < 3; i++) {
1480            // Disable the selection components
1481            // init() will set them appropriately
1482            choices[i].setEnabled(false);
1483            startFields[i].setEnabled(false);
1484            endFields[i].setEnabled(false);
1485            strideFields[i].setEnabled(false);
1486            maxLabels[i].setEnabled(false);
1487        }
1488    }
1489
1490    private void processComboBoxEvent(Combo source)
1491    {
1492        int theSelectedChoice = -1;
1493
1494        int n = Math.min(3, rank);
1495        for (int i = 0; i < n; i++) {
1496            if (source.equals(choices[i])) {
1497                theSelectedChoice = i;
1498            }
1499        }
1500
1501        if (theSelectedChoice < 0) {
1502            return; // the selected ComboBox is not a dimension choice
1503        }
1504
1505        int theIndex = source.getSelectionIndex();
1506        if (theIndex == currentIndex[theSelectedChoice]) {
1507            return; // select the same item, no change
1508        }
1509
1510        start[currentIndex[theSelectedChoice]] = 0;
1511
1512        // reset the selected dimension choice
1513        startFields[theSelectedChoice].setText("0");
1514        endFields[theSelectedChoice].setText(String.valueOf(dims[theIndex] - 1));
1515        strideFields[theSelectedChoice].setText("1");
1516        maxLabels[theSelectedChoice].setText(String.valueOf(dims[theIndex]));
1517
1518        // if the selected choice selects the dimension that is selected by
1519        // other dimension choice, exchange the dimensions
1520        for (int i = 0; i < n; i++) {
1521            if (i == theSelectedChoice) {
1522                continue; // don't exchange itself
1523            }
1524            else if (theIndex == choices[i].getSelectionIndex()) {
1525                choices[i].select(currentIndex[theSelectedChoice]);
1526                startFields[i].setText("0");
1527                endFields[i].setText(String.valueOf(dims[currentIndex[theSelectedChoice]] - 1));
1528                strideFields[i].setText("1");
1529                maxLabels[i].setText(String.valueOf(dims[currentIndex[theSelectedChoice]]));
1530            }
1531        }
1532
1533        for (int i = 0; i < n; i++) {
1534            currentIndex[i] = choices[i].getSelectionIndex();
1535        }
1536
1537        // update the navigator
1538        if (rank > 1) {
1539            int hIdx = choices[0].getSelectionIndex();
1540            int wIdx = choices[1].getSelectionIndex();
1541            transposeChoice.select(0);
1542
1543            // Use transpose option only if the dims are not in original
1544            // order
1545            if (hIdx < wIdx)
1546                transposeChoice.setEnabled(false);
1547            else
1548                transposeChoice.setEnabled(true);
1549
1550            long dims[] = dataObject.getDims();
1551            int w       = (int)dims[wIdx];
1552            int h       = (int)dims[hIdx];
1553
1554            if (navigator != null) {
1555                navigator.setDimensionSize(w, h);
1556                navigator.redraw();
1557            }
1558        }
1559
1560        if (rank > 2) {
1561            endFields[2].setText(startFields[2].getText());
1562        }
1563    }
1564
1565    /**
1566     * PreviewNavigator draws a selection rectangle for selecting a subset
1567     *  of the data to be displayed.
1568     */
1569    private class PreviewNavigator extends Canvas {
1570        private final int NAVIGATOR_SIZE = 150;
1571        private int dimX, dimY, x, y;
1572        private double r;
1573        private Point startPosition; // mouse clicked position
1574        private Rectangle selectedArea;
1575        private Image previewImage = null;
1576        private String selStr;
1577
1578        private PreviewNavigator(Composite parent, int style, int w, int h)
1579        {
1580            super(parent, style);
1581
1582            GridData data   = new GridData(SWT.FILL, SWT.FILL, false, true);
1583            data.widthHint  = NAVIGATOR_SIZE;
1584            data.heightHint = NAVIGATOR_SIZE;
1585            this.setLayoutData(data);
1586
1587            dimX = w;
1588            dimY = h;
1589            if (dimX > dimY) {
1590                x = NAVIGATOR_SIZE;
1591                r = dimX / (double)x;
1592                y = (int)(dimY / r);
1593            }
1594            else {
1595                y = NAVIGATOR_SIZE;
1596                r = dimY / (double)y;
1597                x = (int)(dimX / r);
1598            }
1599
1600            selectedArea = new Rectangle();
1601
1602            selStr = "";
1603
1604            try {
1605                previewImage = createPreviewImage();
1606
1607                String origStr = ViewProperties.getImageOrigin();
1608                if (ViewProperties.ORIGIN_LL.equalsIgnoreCase(origStr))
1609                    flip(DefaultImageView.FLIP_VERTICAL);
1610                else if (ViewProperties.ORIGIN_UR.equalsIgnoreCase(origStr))
1611                    flip(DefaultImageView.FLIP_HORIZONTAL);
1612                else if (ViewProperties.ORIGIN_LR.equalsIgnoreCase(origStr)) {
1613                    rotate(DefaultImageView.ROTATE_CW_90);
1614                    rotate(DefaultImageView.ROTATE_CW_90);
1615                }
1616            }
1617            catch (Exception ex) {
1618                ex.printStackTrace();
1619            }
1620
1621            this.addMouseListener(new MouseListener() {
1622                @Override
1623                public void mouseDoubleClick(MouseEvent e)
1624                {
1625                }
1626
1627                @Override
1628                public void mouseDown(MouseEvent e)
1629                {
1630                    startPosition = new Point(e.x, e.y);
1631                    selectedArea.setBounds(startPosition.x, startPosition.y, 0, 0);
1632                }
1633
1634                @Override
1635                public void mouseUp(MouseEvent e)
1636                {
1637                    if (startPosition.x == e.x && startPosition.y == e.y) {
1638                        selectedArea.setBounds(startPosition.x, startPosition.y, 0, 0);
1639                        redraw();
1640                    }
1641                }
1642            });
1643
1644            this.addMouseMoveListener(new MouseMoveListener() {
1645                @Override
1646                public void mouseMove(MouseEvent e)
1647                {
1648                    if (e.stateMask == SWT.BUTTON1 || e.stateMask == SWT.BUTTON3) {
1649                        Point p0 = startPosition;
1650                        Point p1 = new Point(e.x, e.y);
1651
1652                        int x0 = Math.max(0, Math.min(p0.x, p1.x));
1653                        int y0 = Math.max(0, Math.min(p0.y, p1.y));
1654                        int x1 = Math.min(x, Math.max(p0.x, p1.x));
1655                        int y1 = Math.min(y, Math.max(p0.y, p1.y));
1656
1657                        int w = x1 - x0;
1658                        int h = y1 - y0;
1659
1660                        selectedArea.setBounds(x0, y0, w, h);
1661
1662                        try {
1663                            updateSelection(x0, y0, w, h);
1664                        }
1665                        catch (Exception ex) {
1666                        }
1667
1668                        redraw();
1669                    }
1670                }
1671            });
1672
1673            this.addPaintListener(new PaintListener() {
1674                @Override
1675                public void paintControl(PaintEvent e)
1676                {
1677                    GC gc = e.gc;
1678
1679                    gc.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLUE));
1680
1681                    if (previewImage != null) {
1682                        gc.drawImage(convertBufferedImageToSWTImage((BufferedImage)previewImage), 0, 0);
1683                    }
1684                    else {
1685                        gc.fillRectangle(0, 0, x, y);
1686                    }
1687
1688                    int w = selectedArea.width;
1689                    int h = selectedArea.height;
1690                    if ((w > 0) && (h > 0)) {
1691                        gc.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
1692                        gc.drawRectangle(selectedArea.x, selectedArea.y, w, h);
1693                    }
1694
1695                    org.eclipse.swt.graphics.Rectangle bounds = ((Canvas)e.widget).getBounds();
1696                    Point textSize                            = gc.stringExtent(selStr);
1697                    gc.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
1698                    gc.drawString(selStr, (bounds.width / 2) - (textSize.x / 2),
1699                                  bounds.height - textSize.y - 4);
1700                }
1701            });
1702        }
1703
1704        private Image createPreviewImage() throws Exception
1705        {
1706            if ((rank <= 1) || !(dataObject instanceof ScalarDS)) {
1707                return null;
1708            }
1709
1710            Image preImage = null;
1711            ScalarDS sd    = (ScalarDS)dataObject;
1712
1713            if (sd.getDatatype().isText()) {
1714                return null;
1715            }
1716
1717            // backup the selection
1718            long[] strideBackup       = new long[rank];
1719            long[] selectedBackup     = new long[rank];
1720            long[] startBackup        = new long[rank];
1721            int[] selectedIndexBackup = new int[3];
1722            System.arraycopy(stride, 0, strideBackup, 0, rank);
1723            System.arraycopy(selected, 0, selectedBackup, 0, rank);
1724            System.arraycopy(start, 0, startBackup, 0, rank);
1725            System.arraycopy(selectedIndex, 0, selectedIndexBackup, 0, 3);
1726
1727            // set the selection for preview
1728            for (int i = 0; i < rank; i++) {
1729                start[i]    = 0;
1730                stride[i]   = 1;
1731                selected[i] = 1;
1732            }
1733
1734            if (choices != null) {
1735                try {
1736                    selectedIndex[0] = choices[0].getSelectionIndex();
1737                    selectedIndex[1] = choices[1].getSelectionIndex();
1738                }
1739                catch (Exception ex) {
1740                }
1741            }
1742            long steps                 = (long)Math.ceil(r);
1743            selected[selectedIndex[0]] = (dims[selectedIndex[0]] / steps);
1744            selected[selectedIndex[1]] = (dims[selectedIndex[1]] / steps);
1745            stride[selectedIndex[0]] = stride[selectedIndex[1]] = steps;
1746
1747            if (selected[selectedIndex[0]] == 0) {
1748                selected[selectedIndex[0]] = 1;
1749            }
1750            if (selected[selectedIndex[1]] == 0) {
1751                selected[selectedIndex[1]] = 1;
1752            }
1753
1754            if (isTrueColorImage && (start.length > 2)) {
1755                start[selectedIndex[2]]    = 0;
1756                selected[selectedIndex[2]] = 3;
1757                stride[selectedIndex[2]]   = 1;
1758            }
1759
1760            // update the ratio of preview image size to the real dataset
1761            y = (int)selected[selectedIndex[0]];
1762            x = (int)selected[selectedIndex[1]];
1763            r = Math.min((double)dims[selectedIndex[0]] / (double)selected[selectedIndex[0]],
1764                         (double)dims[selectedIndex[1]] / (double)selected[selectedIndex[1]]);
1765
1766            try {
1767                Object data = sd.read();
1768                int h       = (int)sd.getHeight();
1769                int w       = (int)sd.getWidth();
1770
1771                byte[] bData = Tools.getBytes(data, sd.getImageDataRange(), w, h, false,
1772                                              sd.getFilteredImageValues(), null);
1773
1774                if (isTrueColorImage) {
1775                    boolean isPlaneInterlace = (sd.getInterlace() == ScalarDS.INTERLACE_PLANE);
1776                    preImage                 = Tools.createTrueColorImage(bData, isPlaneInterlace, w, h);
1777                }
1778                else {
1779                    byte[][] imagePalette = sd.getPalette();
1780                    if (imagePalette == null) {
1781                        imagePalette = Tools.createGrayPalette();
1782                    }
1783
1784                    if ((isH5 || (rank > 2)) && (selectedIndex[0] > selectedIndex[1])) {
1785                        // transpose data
1786                        int n         = bData.length;
1787                        byte[] bData2 = new byte[n];
1788                        for (int i = 0; i < h; i++) {
1789                            for (int j = 0; j < w; j++) {
1790                                bData[i * w + j] = bData2[j * h + i];
1791                            }
1792                        }
1793                    }
1794                    if (!isH5 && !sd.isDefaultImageOrder() && (selectedIndex[1] > selectedIndex[0])) {
1795                        // transpose data for hdf4 images where selectedIndex[1]
1796                        // > selectedIndex[0]
1797                        int n         = bData.length;
1798                        byte[] bData2 = new byte[n];
1799                        for (int i = 0; i < h; i++) {
1800                            for (int j = 0; j < w; j++) {
1801                                bData[i * w + j] = bData2[j * h + i];
1802                            }
1803                        }
1804                    }
1805                    preImage = Tools.createIndexedImage(null, bData, imagePalette, w, h);
1806                }
1807            }
1808            finally {
1809                // set back the original selection
1810                System.arraycopy(strideBackup, 0, stride, 0, rank);
1811                System.arraycopy(selectedBackup, 0, selected, 0, rank);
1812                System.arraycopy(startBackup, 0, start, 0, rank);
1813                System.arraycopy(selectedIndexBackup, 0, selectedIndex, 0, 3);
1814            }
1815
1816            return preImage;
1817        }
1818
1819        private void updateSelection(int x0, int y0, int w, int h)
1820        {
1821            int i0 = 0, i1 = 0;
1822
1823            i0 = (int)(y0 * r);
1824            if (i0 > dims[currentIndex[0]]) {
1825                i0 = (int)dims[currentIndex[0]];
1826            }
1827            startFields[0].setText(String.valueOf(i0));
1828
1829            i1 = (int)((y0 + h) * r);
1830
1831            if (i1 < i0) {
1832                i1 = i0;
1833            }
1834            endFields[0].setText(String.valueOf(i1));
1835
1836            selStr = String.valueOf((int)(h * r));
1837
1838            if (rank > 1) {
1839                i0 = (int)(x0 * r);
1840                if (i0 > dims[currentIndex[1]]) {
1841                    i0 = (int)dims[currentIndex[1]];
1842                }
1843                startFields[1].setText(String.valueOf(i0));
1844
1845                i1 = (int)((x0 + w) * r);
1846                if (i1 < i0) {
1847                    i1 = i0;
1848                }
1849                endFields[1].setText(String.valueOf(i1));
1850
1851                selStr += " x " + ((int)(w * r));
1852            }
1853        }
1854
1855        private void setDimensionSize(int w, int h)
1856        {
1857            dimX = w;
1858            dimY = h;
1859            if (dimX > dimY) {
1860                x = NAVIGATOR_SIZE;
1861                r = dimX / (double)x;
1862                y = (int)(dimY / r);
1863            }
1864            else {
1865                y = NAVIGATOR_SIZE;
1866                r = dimY / (double)y;
1867                x = (int)(dimX / r);
1868            }
1869
1870            selectedArea.setSize(0, 0);
1871
1872            try {
1873                previewImage = createPreviewImage();
1874            }
1875            catch (Exception ex) {
1876            }
1877
1878            this.redraw();
1879        }
1880
1881        private boolean applyImageFilter(ImageFilter filter)
1882        {
1883            boolean status              = true;
1884            ImageProducer imageProducer = previewImage.getSource();
1885
1886            try {
1887                previewImage = Tools.toBufferedImage(
1888                    Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(imageProducer, filter)));
1889            }
1890            catch (Exception err) {
1891                shell.getDisplay().beep();
1892                Tools.showError(shell, "Apply Image Filter", err.getMessage());
1893                status = false;
1894            }
1895
1896            return status;
1897        }
1898
1899        private void flip(int direction) { applyImageFilter(new FlipFilter(direction)); }
1900
1901        private void rotate(int direction)
1902        {
1903            if (!(direction == DefaultImageView.ROTATE_CW_90 || direction == DefaultImageView.ROTATE_CCW_90))
1904                return;
1905
1906            applyImageFilter(new Rotate90Filter(direction));
1907        }
1908
1909        /**
1910         * Converts a given BufferedImage to ImageData for a SWT-readable Image
1911         *
1912         * @param image The BufferedImage to be converted
1913         *
1914         * @return the Image
1915         */
1916        private org.eclipse.swt.graphics.Image convertBufferedImageToSWTImage(BufferedImage image)
1917        {
1918            Display display = this.getDisplay();
1919
1920            if (image.getColorModel() instanceof DirectColorModel) {
1921                DirectColorModel colorModel = (DirectColorModel)image.getColorModel();
1922                PaletteData palette = new PaletteData(colorModel.getRedMask(), colorModel.getGreenMask(),
1923                                                      colorModel.getBlueMask());
1924                ImageData data =
1925                    new ImageData(image.getWidth(), image.getHeight(), colorModel.getPixelSize(), palette);
1926
1927                for (int y = 0; y < data.height; y++) {
1928                    for (int x = 0; x < data.width; x++) {
1929                        int rgb = image.getRGB(x, y);
1930                        int pixel =
1931                            palette.getPixel(new RGB((rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF, rgb & 0xFF));
1932                        data.setPixel(x, y, pixel);
1933                        if (colorModel.hasAlpha()) {
1934                            data.setAlpha(x, y, (rgb >> 24) & 0xFF);
1935                        }
1936                    }
1937                }
1938
1939                return new org.eclipse.swt.graphics.Image(display, data);
1940            }
1941            else if (image.getColorModel() instanceof IndexColorModel) {
1942                IndexColorModel colorModel = (IndexColorModel)image.getColorModel();
1943                int size                   = colorModel.getMapSize();
1944                byte[] reds                = new byte[size];
1945                byte[] greens              = new byte[size];
1946                byte[] blues               = new byte[size];
1947                colorModel.getReds(reds);
1948                colorModel.getGreens(greens);
1949                colorModel.getBlues(blues);
1950                RGB[] rgbs = new RGB[size];
1951                for (int i = 0; i < rgbs.length; i++) {
1952                    rgbs[i] = new RGB(reds[i] & 0xFF, greens[i] & 0xFF, blues[i] & 0xFF);
1953                }
1954                PaletteData palette = new PaletteData(rgbs);
1955                ImageData data =
1956                    new ImageData(image.getWidth(), image.getHeight(), colorModel.getPixelSize(), palette);
1957                data.transparentPixel = colorModel.getTransparentPixel();
1958                WritableRaster raster = image.getRaster();
1959                int[] pixelArray      = new int[1];
1960                for (int y = 0; y < data.height; y++) {
1961                    for (int x = 0; x < data.width; x++) {
1962                        raster.getPixel(x, y, pixelArray);
1963                        data.setPixel(x, y, pixelArray[0]);
1964                    }
1965                }
1966
1967                return new org.eclipse.swt.graphics.Image(display, data);
1968            }
1969            else if (image.getColorModel() instanceof ComponentColorModel) {
1970                ComponentColorModel colorModel = (ComponentColorModel)image.getColorModel();
1971                // ASSUMES: 3 BYTE BGR IMAGE TYPE
1972                PaletteData palette = new PaletteData(0x0000FF, 0x00FF00, 0xFF0000);
1973                ImageData data =
1974                    new ImageData(image.getWidth(), image.getHeight(), colorModel.getPixelSize(), palette);
1975                // This is valid because we are using a 3-byte Data model with no transparent pixels
1976                data.transparentPixel = -1;
1977                WritableRaster raster = image.getRaster();
1978                int[] pixelArray      = new int[3];
1979                for (int y = 0; y < data.height; y++) {
1980                    for (int x = 0; x < data.width; x++) {
1981                        raster.getPixel(x, y, pixelArray);
1982                        int pixel = palette.getPixel(new RGB(pixelArray[0], pixelArray[1], pixelArray[2]));
1983                        data.setPixel(x, y, pixel);
1984                    }
1985                }
1986                return new org.eclipse.swt.graphics.Image(display, data);
1987            }
1988
1989            return null;
1990        }
1991    }
1992}