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    /**
704     * Check if the display option is image
705     *
706     * @return true if the display option is image.
707     */
708    public boolean isImageDisplay() { return isImageDisplay; }
709
710    /**
711     * Check if the index starts with 0
712     *
713     * @return true if the index starts with 0.
714     */
715    public boolean isIndexBase1() { return isIndexBase1; }
716
717    /**
718     * Get the bitmask value
719     *
720     * @return the bitmask.
721     */
722    public BitSet getBitmask()
723    {
724        if (bitmask == null)
725            return null;
726
727        // do not use bitmask if it is empty (all bits are zero)
728        if (bitmask.isEmpty())
729            return null;
730
731        boolean isAllSelected = true;
732        int size              = bitmask.size();
733        for (int i = 0; i < size; i++)
734            isAllSelected = (bitmask.get(i) && isAllSelected);
735
736        // do not use bitmask if it is full (all bits are one)
737        if (isAllSelected)
738            return null;
739
740        return bitmask;
741    }
742
743    /**
744     * Get the name of the datatview
745     *
746     * @return the name of the selected dataview
747     */
748    public String getDataViewName() { return dataViewName; }
749
750    /**
751     * Check if the data should display as characters
752     *
753     * @return true if display the data as characters; otherwise, display as numbers.
754     */
755    public boolean isDisplayTypeChar() { return isDisplayTypeChar; }
756
757    /**
758     * Check if only the bitmask should be applied
759     *
760     * @return if it only apply bitmask.
761     */
762    public boolean isApplyBitmaskOnly() { return isApplyBitmaskOnly; }
763
764    /**
765     * Check if the data in 2D table is to be transposed
766     *
767     * @return true if transpose the data in 2D table; otherwise, do not transpose the data.
768     */
769    public boolean isTransposed() { return isTransposed; }
770
771    /**
772     * Check if the data selection is cancelled
773     *
774     * @return true if the data selection is cancelled.
775     */
776    public boolean isCancelled() { return isSelectionCancelled; }
777
778    private void createScalarDSContents()
779    {
780        // Create display type region
781        org.eclipse.swt.widgets.Group displayAsGroup = new org.eclipse.swt.widgets.Group(shell, SWT.NONE);
782        displayAsGroup.setFont(curFont);
783        displayAsGroup.setText("Display As");
784        displayAsGroup.setLayout(new GridLayout(1, true));
785        displayAsGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
786
787        Composite spreadsheetComposite = new Composite(displayAsGroup, SWT.BORDER);
788        spreadsheetComposite.setLayout(new GridLayout(2, false));
789        spreadsheetComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
790
791        spreadsheetButton = new Button(spreadsheetComposite, SWT.RADIO);
792        spreadsheetButton.setFont(curFont);
793        spreadsheetButton.setText("&Spreadsheet");
794        spreadsheetButton.setSelection(true);
795        spreadsheetButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
796        spreadsheetButton.addSelectionListener(new SelectionAdapter() {
797            @Override
798            public void widgetSelected(SelectionEvent e)
799            {
800                imageButton.setSelection(!spreadsheetButton.getSelection());
801                choicePalette.setEnabled(false);
802                choiceImageView.setEnabled(false);
803                choiceTableView.setEnabled(true);
804                dataRangeField.setEnabled(false);
805                fillValueField.setEnabled(false);
806                Datatype dtype = dataObject.getDatatype();
807                charCheckbox.setEnabled((dtype.isChar() || dtype.isInteger()) &&
808                                        (dtype.getDatatypeSize() == 1));
809            }
810        });
811
812        charCheckbox = new Button(spreadsheetComposite, SWT.CHECK);
813        charCheckbox.setFont(curFont);
814        charCheckbox.setText("Show As &Char");
815        charCheckbox.setSelection(false);
816        charCheckbox.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
817
818        if (dataObject.getDatatype().isChar() ||
819            (dataObject.getDatatype().isInteger() && dataObject.getDatatype().getDatatypeSize() == 1)) {
820            charCheckbox.setEnabled(false);
821        }
822
823        Label label = new Label(spreadsheetComposite, SWT.RIGHT);
824        label.setFont(curFont);
825        label.setText("TableView: ");
826
827        choiceTableView = new Combo(spreadsheetComposite, SWT.SINGLE | SWT.DROP_DOWN | SWT.READ_ONLY);
828        choiceTableView.setFont(curFont);
829        choiceTableView.setItems(HDFView.getListOfTableViews().toArray(new String[0]));
830        choiceTableView.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
831        choiceTableView.select(0);
832
833        Composite imageComposite = new Composite(displayAsGroup, SWT.BORDER);
834        imageComposite.setLayout(new GridLayout(4, false));
835        imageComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
836
837        imageButton = new Button(imageComposite, SWT.RADIO);
838        imageButton.setFont(curFont);
839        imageButton.setText("&Image");
840        imageButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
841        imageButton.addSelectionListener(new SelectionAdapter() {
842            @Override
843            public void widgetSelected(SelectionEvent e)
844            {
845                spreadsheetButton.setSelection(!imageButton.getSelection());
846                choicePalette.setEnabled(!isTrueColorImage);
847                dataRangeField.setEnabled(true);
848                fillValueField.setEnabled(true);
849                choiceImageView.setEnabled(true);
850                choiceTableView.setEnabled(false);
851                charCheckbox.setSelection(false);
852                charCheckbox.setEnabled(false);
853            }
854        });
855
856        choicePalette = new Combo(imageComposite, SWT.SINGLE | SWT.DROP_DOWN | SWT.READ_ONLY);
857        choicePalette.setFont(curFont);
858        choicePalette.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
859
860        choicePalette.add("Select palette");
861
862        if (dataObject instanceof ScalarDS) {
863            String paletteName = ((ScalarDS)dataObject).getPaletteName(0);
864            if (paletteName == null) {
865                paletteName = "Default";
866            }
867            choicePalette.add(paletteName);
868            for (int i = 2; i <= numberOfPalettes; i++) {
869                paletteName = ((ScalarDS)dataObject).getPaletteName(i - 1);
870                choicePalette.add(paletteName);
871            }
872        }
873        choicePalette.add("Gray");
874        choicePalette.add("ReverseGray");
875        choicePalette.add("GrayWave");
876        choicePalette.add("Rainbow");
877        choicePalette.add("Nature");
878        choicePalette.add("Wave");
879
880        choicePalette.select(0);
881
882        label = new Label(imageComposite, SWT.RIGHT);
883        label.setFont(curFont);
884        label.setText("Valid Range: ");
885
886        dataRangeField = new Text(imageComposite, SWT.SINGLE | SWT.BORDER);
887        dataRangeField.setFont(curFont);
888        dataRangeField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
889
890        String minmaxStr = "min, max";
891
892        double[] minmax = ((ScalarDS)dataObject).getImageDataRange();
893        if (minmax != null) {
894            if (dataObject.getDatatype().isFloat())
895                minmaxStr = minmax[0] + "," + minmax[1];
896            else
897                minmaxStr = ((long)minmax[0]) + "," + ((long)minmax[1]);
898        }
899
900        dataRangeField.setText(minmaxStr);
901
902        label = new Label(imageComposite, SWT.RIGHT);
903        label.setFont(curFont);
904        label.setText("ImageView: ");
905
906        choiceImageView = new Combo(imageComposite, SWT.SINGLE | SWT.DROP_DOWN | SWT.READ_ONLY);
907        choiceImageView.setFont(curFont);
908        choiceImageView.setItems(HDFView.getListOfImageViews().toArray(new String[0]));
909        choiceImageView.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
910        choiceImageView.select(0);
911
912        label = new Label(imageComposite, SWT.RIGHT);
913        label.setFont(curFont);
914        label.setText("Invalid Values: ");
915
916        fillValueField = new Text(imageComposite, SWT.SINGLE | SWT.BORDER);
917        fillValueField.setFont(curFont);
918        fillValueField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
919
920        String fillStr = "val1, val2, ...";
921
922        java.util.List<Number> fillValue = ((ScalarDS)dataObject).getFilteredImageValues();
923        int n                            = fillValue.size();
924        if (n > 0) {
925            fillStr = fillValue.get(0).toString();
926            for (int i = 1; i < n; i++) {
927                fillStr += ", " + fillValue.get(i);
928            }
929        }
930
931        fillValueField.setText(fillStr);
932
933        // Create Index Base region
934        org.eclipse.swt.widgets.Group indexBaseGroup = new org.eclipse.swt.widgets.Group(shell, SWT.NONE);
935        indexBaseGroup.setFont(curFont);
936        indexBaseGroup.setText("Index Base");
937        indexBaseGroup.setLayout(new GridLayout(2, true));
938        indexBaseGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
939
940        base0Button = new Button(indexBaseGroup, SWT.RADIO);
941        base0Button.setFont(curFont);
942        base0Button.setText("0-based");
943        base0Button.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
944
945        base1Button = new Button(indexBaseGroup, SWT.RADIO);
946        base1Button.setFont(curFont);
947        base1Button.setText("1-based");
948        base1Button.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
949
950        if (ViewProperties.isIndexBase1()) {
951            base0Button.setSelection(false);
952            base1Button.setSelection(true);
953        }
954        else {
955            base0Button.setSelection(true);
956            base1Button.setSelection(false);
957        }
958
959        // Create Bitmask region
960        org.eclipse.swt.widgets.Group bitmaskGroup = new org.eclipse.swt.widgets.Group(shell, SWT.NONE);
961        bitmaskGroup.setFont(curFont);
962        bitmaskGroup.setText("Bitmask");
963        bitmaskGroup.setLayout(new GridLayout(2, false));
964        bitmaskGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
965
966        extractBitButton = new Button(bitmaskGroup, SWT.CHECK);
967        extractBitButton.setFont(curFont);
968        extractBitButton.setText("Show &Value of Selected Bits");
969        extractBitButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
970        extractBitButton.setSelection(false);
971        extractBitButton.addSelectionListener(new SelectionAdapter() {
972            @Override
973            public void widgetSelected(SelectionEvent e)
974            {
975                boolean selected = extractBitButton.getSelection();
976
977                if (selected) {
978                    if (applyBitmaskButton.getSelection()) {
979                        applyBitmaskButton.setSelection(false);
980                    }
981
982                    if (!bitmaskButtons[0].getEnabled()) {
983                        for (int i = 0; i < bitmaskButtons.length; i++) {
984                            bitmaskButtons[i].setEnabled(true);
985                        }
986                    }
987
988                    int n = 0;
989
990                    if (bitmaskButtons[0].getSelection())
991                        n = 1;
992
993                    for (int i = 1; i < bitmaskButtons.length; i++) {
994                        if (bitmaskButtons[i].getSelection() && !bitmaskButtons[i - 1].getSelection()) {
995                            n++;
996                        }
997                    }
998
999                    if (n > 1) {
1000                        extractBitButton.setSelection(false);
1001                        applyBitmaskButton.setSelection(true);
1002
1003                        Tools.showError(
1004                            shell, "Select",
1005                            "Selecting non-adjacent bits is only allowed \nfor the \"Apply Bitmask\" option.");
1006                        return;
1007                    }
1008                }
1009                else {
1010                    for (int i = 0; i < bitmaskButtons.length; i++) {
1011                        bitmaskButtons[i].setEnabled(false);
1012                    }
1013                }
1014            }
1015        });
1016
1017        bitmaskHelp = new Button(bitmaskGroup, SWT.PUSH);
1018        bitmaskHelp.setImage(ViewProperties.getHelpIcon());
1019        bitmaskHelp.setToolTipText("Help on how to set bitmask");
1020        bitmaskHelp.setLayoutData(new GridData(SWT.END, SWT.FILL, false, false));
1021        bitmaskHelp.setEnabled(false);
1022        bitmaskHelp.addSelectionListener(new SelectionAdapter() {
1023            @Override
1024            public void widgetSelected(SelectionEvent e)
1025            {
1026                String msg = ""
1027                             + "\"Apply Bitmask\" applies bitwise \"AND\" to the original data.\n"
1028                             + "For example, bits 2, 3, and 4 are selected for the bitmask\n"
1029                             + "         10010101 (data)\n"
1030                             + "AND 00011100 (mask)  \n"
1031                             + "  =     00010100 (result) ==> the decimal value is 20. \n"
1032                             + "\n"
1033                             + "\"Extract Bit(s)\" removes all the bits from the result above where\n"
1034                             + "their corresponding bits in the bitmask are 0. \nFor the same example above, "
1035                             + "the result is \n101 ==> the decimal value is 5.\n\n";
1036
1037                Tools.showInformation(shell, "Help", msg);
1038            }
1039        });
1040
1041        applyBitmaskButton = new Button(bitmaskGroup, SWT.CHECK);
1042        applyBitmaskButton.setFont(curFont);
1043        applyBitmaskButton.setText("&Apply Bitmask");
1044        applyBitmaskButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
1045        applyBitmaskButton.setSelection(false);
1046        applyBitmaskButton.addSelectionListener(new SelectionAdapter() {
1047            @Override
1048            public void widgetSelected(SelectionEvent e)
1049            {
1050                if (extractBitButton.getSelection()) {
1051                    extractBitButton.setSelection(false);
1052                }
1053                else if (!applyBitmaskButton.getSelection()) {
1054                    for (int i = 0; i < bitmaskButtons.length; i++) {
1055                        bitmaskButtons[i].setEnabled(false);
1056                    }
1057                }
1058                else {
1059                    if (!bitmaskButtons[0].getEnabled()) {
1060                        for (int i = 0; i < bitmaskButtons.length; i++) {
1061                            bitmaskButtons[i].setEnabled(true);
1062                        }
1063                    }
1064                }
1065            }
1066        });
1067
1068        new Label(bitmaskGroup, SWT.RIGHT).setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
1069
1070        Composite buttonComposite = new Composite(bitmaskGroup, SWT.NO_RADIO_GROUP);
1071        buttonComposite.setLayout(new GridLayout(16, true));
1072        buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
1073
1074        int tsize;
1075
1076        if (dataObject.getDatatype().isArray()) {
1077            Datatype baseType = dataObject.getDatatype().getDatatypeBase();
1078
1079            while (baseType.isArray()) {
1080                baseType = baseType.getDatatypeBase();
1081            }
1082
1083            tsize = (int)baseType.getDatatypeSize();
1084        }
1085        else {
1086            tsize = (int)dataObject.getDatatype().getDatatypeSize();
1087        }
1088
1089        bitmaskButtons =
1090            (tsize >= 0 && !dataObject.getDatatype().isText()) ? new Button[8 * tsize] : new Button[0];
1091
1092        for (int i = 0; i < bitmaskButtons.length; i++) {
1093            bitmaskButtons[i] = new Button(buttonComposite, SWT.RADIO);
1094            bitmaskButtons[i].setFont(curFont);
1095            bitmaskButtons[i].setText(String.valueOf(bitmaskButtons.length - i - 1));
1096            bitmaskButtons[i].setEnabled(false);
1097            bitmaskButtons[i].addSelectionListener(new SelectionAdapter() {
1098                @Override
1099                public void widgetSelected(SelectionEvent e)
1100                {
1101                    if (extractBitButton.getSelection()) {
1102                        Button source = (Button)e.widget;
1103
1104                        // Don't allow non-adjacent selection of bits when extracting bits
1105                        int n = 0;
1106
1107                        if (bitmaskButtons[0].getSelection())
1108                            n = 1;
1109
1110                        for (int i = 1; i < bitmaskButtons.length; i++) {
1111                            if (bitmaskButtons[i].getSelection() && !bitmaskButtons[i - 1].getSelection()) {
1112                                n++;
1113                            }
1114                        }
1115
1116                        if (n > 1) {
1117                            Tools.showError(
1118                                shell, "Select",
1119                                "Please select contiguous bits \nwhen the \"Show Value of Selected Bits\" option is checked.");
1120
1121                            source.setSelection(false);
1122                            return;
1123                        }
1124                    }
1125                }
1126            });
1127        }
1128
1129        if (dataObject.getDatatype().isChar() || (dataObject.getDatatype().isInteger() && tsize <= 8)) {
1130            extractBitButton.setEnabled(true);
1131            applyBitmaskButton.setEnabled(true);
1132            bitmaskHelp.setEnabled(true);
1133        }
1134
1135        // Create Dimension/Subset selection region
1136        org.eclipse.swt.widgets.Group dimSubGroup = new org.eclipse.swt.widgets.Group(shell, SWT.NONE);
1137        dimSubGroup.setFont(curFont);
1138        dimSubGroup.setText("Dimension and Subset Selection");
1139        dimSubGroup.setLayout(new GridLayout(2, false));
1140        dimSubGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
1141
1142        int h = 1, w = 1;
1143        h = (int)dims[selectedIndex[0]];
1144        if (rank > 1) {
1145            w = (int)dims[selectedIndex[1]];
1146        }
1147
1148        if (rank > 1) {
1149            navigator = new PreviewNavigator(dimSubGroup, SWT.DOUBLE_BUFFERED | SWT.BORDER, w, h);
1150        }
1151        else {
1152            dimSubGroup.setLayout(new GridLayout(1, true));
1153        }
1154
1155        createDimSubSelectionComposite(dimSubGroup);
1156    }
1157
1158    private void createCompoundDSContents()
1159    {
1160        Composite content = new Composite(shell, SWT.NONE);
1161        content.setLayout(new GridLayout(2, false));
1162        content.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
1163
1164        org.eclipse.swt.widgets.Group membersGroup = new org.eclipse.swt.widgets.Group(content, SWT.NONE);
1165        membersGroup.setFont(curFont);
1166        membersGroup.setText("Select Members");
1167        membersGroup.setLayout(new GridLayout(1, true));
1168        membersGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, true));
1169
1170        final String[] names = ((CompoundDS)dataObject).getMemberNames();
1171        String[] columnNames = new String[names.length];
1172        for (int i = 0; i < names.length; i++) {
1173            columnNames[i] = new String(names[i]);
1174            columnNames[i] = columnNames[i].replaceAll(CompoundDS.SEPARATOR, "->");
1175        }
1176        fieldList = new List(membersGroup, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL);
1177        fieldList.setFont(curFont);
1178        fieldList.setItems(columnNames);
1179        fieldList.selectAll();
1180
1181        GridData data   = new GridData(SWT.FILL, SWT.FILL, false, true);
1182        data.heightHint = fieldList.getItemHeight() * 10;
1183        data.widthHint  = fieldList.computeSize(SWT.DEFAULT, SWT.DEFAULT).x + 10;
1184        fieldList.setLayoutData(data);
1185
1186        org.eclipse.swt.widgets.Group dimSubGroup = new org.eclipse.swt.widgets.Group(content, SWT.NONE);
1187        dimSubGroup.setFont(curFont);
1188        dimSubGroup.setText("Dimension and Subset Selection");
1189        dimSubGroup.setLayout(new GridLayout());
1190        dimSubGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
1191
1192        createDimSubSelectionComposite(dimSubGroup);
1193
1194        Composite tableViewComposite = new Composite(dimSubGroup, SWT.BORDER);
1195        tableViewComposite.setLayout(new GridLayout(2, false));
1196        tableViewComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
1197
1198        Label label = new Label(tableViewComposite, SWT.RIGHT);
1199        label.setFont(curFont);
1200        label.setText("TableView: ");
1201
1202        choiceTableView = new Combo(tableViewComposite, SWT.SINGLE | SWT.DROP_DOWN | SWT.READ_ONLY);
1203        choiceTableView.setFont(curFont);
1204        choiceTableView.setItems(HDFView.getListOfTableViews().toArray(new String[0]));
1205        choiceTableView.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
1206        choiceTableView.select(0);
1207    }
1208
1209    private void createDimSubSelectionComposite(Composite parent)
1210    {
1211        String[] dimNames = ((Dataset)dataObject).getDimNames();
1212
1213        Composite selectionComposite = new Composite(parent, SWT.BORDER);
1214        selectionComposite.setLayout(new GridLayout(6, true));
1215        selectionComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
1216
1217        new Label(selectionComposite, SWT.RIGHT).setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
1218
1219        if (rank > 1) {
1220            transposeChoice = new Combo(selectionComposite, SWT.SINGLE | SWT.READ_ONLY);
1221            transposeChoice.setFont(curFont);
1222            transposeChoice.setLayoutData(new GridData(SWT.FILL, SWT.END, true, false));
1223
1224            transposeChoice.add("Transpose");
1225            transposeChoice.add("Reshape");
1226
1227            transposeChoice.select(0);
1228        }
1229        else {
1230            new Label(selectionComposite, SWT.RIGHT)
1231                .setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
1232        }
1233
1234        Label label = new Label(selectionComposite, SWT.RIGHT);
1235        label.setFont(curFont);
1236        label.setText("Start: ");
1237        label.setLayoutData(new GridData(SWT.CENTER, SWT.END, true, true));
1238
1239        label = new Label(selectionComposite, SWT.RIGHT);
1240        label.setFont(curFont);
1241        label.setText("End: ");
1242        label.setLayoutData(new GridData(SWT.CENTER, SWT.END, true, true));
1243
1244        label = new Label(selectionComposite, SWT.RIGHT);
1245        label.setFont(curFont);
1246        label.setText("Stride: ");
1247        label.setLayoutData(new GridData(SWT.CENTER, SWT.END, true, true));
1248
1249        label = new Label(selectionComposite, SWT.RIGHT);
1250        label.setFont(curFont);
1251        label.setText("Max Size");
1252        label.setLayoutData(new GridData(SWT.CENTER, SWT.END, true, true));
1253
1254        // Create Height selection row
1255        label = new Label(selectionComposite, SWT.RIGHT);
1256        label.setFont(curFont);
1257        label.setText("Height: ");
1258        label.setLayoutData(new GridData(SWT.END, SWT.CENTER, true, true));
1259
1260        choices[0] = new Combo(selectionComposite, SWT.SINGLE | SWT.READ_ONLY);
1261        choices[0].setFont(curFont);
1262        choices[0].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1263        choices[0].addSelectionListener(new SelectionAdapter() {
1264            @Override
1265            public void widgetSelected(SelectionEvent e)
1266            {
1267                Combo source = (Combo)e.widget;
1268
1269                processComboBoxEvent(source);
1270            }
1271        });
1272
1273        for (int j = 0; j < rank; j++) {
1274            if (dimNames == null) {
1275                choices[0].add("dim " + j);
1276            }
1277            else {
1278                choices[0].add(dimNames[j]);
1279            }
1280        }
1281
1282        choices[0].select(0);
1283
1284        startFields[0] = new Text(selectionComposite, SWT.SINGLE | SWT.BORDER);
1285        startFields[0].setFont(curFont);
1286        startFields[0].setText("0");
1287        startFields[0].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1288
1289        endFields[0] = new Text(selectionComposite, SWT.SINGLE | SWT.BORDER);
1290        endFields[0].setFont(curFont);
1291        endFields[0].setText("0");
1292        endFields[0].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1293
1294        strideFields[0] = new Text(selectionComposite, SWT.SINGLE | SWT.BORDER);
1295        strideFields[0].setFont(curFont);
1296        strideFields[0].setText("1");
1297        strideFields[0].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1298
1299        maxLabels[0] = new Label(selectionComposite, SWT.NONE);
1300        maxLabels[0].setFont(curFont);
1301        maxLabels[0].setText("1");
1302        maxLabels[0].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1303
1304        // Create Width selection row
1305        label = new Label(selectionComposite, SWT.RIGHT);
1306        label.setFont(curFont);
1307        label.setText("Width: ");
1308        label.setLayoutData(new GridData(SWT.END, SWT.CENTER, true, true));
1309
1310        choices[1] = new Combo(selectionComposite, SWT.SINGLE | SWT.READ_ONLY);
1311        choices[1].setFont(curFont);
1312        choices[1].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1313        choices[1].addSelectionListener(new SelectionAdapter() {
1314            @Override
1315            public void widgetSelected(SelectionEvent e)
1316            {
1317                Combo source = (Combo)e.widget;
1318
1319                processComboBoxEvent(source);
1320            }
1321        });
1322
1323        for (int j = 0; j < rank; j++) {
1324            if (dimNames == null) {
1325                choices[1].add("dim " + j);
1326            }
1327            else {
1328                choices[1].add(dimNames[j]);
1329            }
1330        }
1331
1332        choices[1].select(0);
1333
1334        startFields[1] = new Text(selectionComposite, SWT.SINGLE | SWT.BORDER);
1335        startFields[1].setFont(curFont);
1336        startFields[1].setText("0");
1337        startFields[1].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1338
1339        endFields[1] = new Text(selectionComposite, SWT.SINGLE | SWT.BORDER);
1340        endFields[1].setFont(curFont);
1341        endFields[1].setText("0");
1342        endFields[1].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1343
1344        strideFields[1] = new Text(selectionComposite, SWT.SINGLE | SWT.BORDER);
1345        strideFields[1].setFont(curFont);
1346        strideFields[1].setText("1");
1347        strideFields[1].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1348
1349        maxLabels[1] = new Label(selectionComposite, SWT.NONE);
1350        maxLabels[1].setFont(curFont);
1351        maxLabels[1].setText("1");
1352        maxLabels[1].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1353
1354        // Create Depth selection row
1355        label = new Label(selectionComposite, SWT.RIGHT);
1356        label.setFont(curFont);
1357        label.setText("Depth: ");
1358        label.setLayoutData(new GridData(SWT.END, SWT.CENTER, true, true));
1359
1360        choices[2] = new Combo(selectionComposite, SWT.SINGLE | SWT.READ_ONLY);
1361        choices[2].setFont(curFont);
1362        choices[2].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1363        choices[2].addSelectionListener(new SelectionAdapter() {
1364            @Override
1365            public void widgetSelected(SelectionEvent e)
1366            {
1367                Combo source = (Combo)e.widget;
1368
1369                processComboBoxEvent(source);
1370            }
1371        });
1372
1373        for (int j = 0; j < rank; j++) {
1374            if (dimNames == null) {
1375                choices[2].add("dim " + j);
1376            }
1377            else {
1378                choices[2].add(dimNames[j]);
1379            }
1380        }
1381
1382        choices[2].select(0);
1383
1384        startFields[2] = new Text(selectionComposite, SWT.SINGLE | SWT.BORDER);
1385        startFields[2].setFont(curFont);
1386        startFields[2].setText("0");
1387        startFields[2].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1388
1389        endFields[2] = new Text(selectionComposite, SWT.SINGLE | SWT.BORDER);
1390        endFields[2].setFont(curFont);
1391        endFields[2].setText("0");
1392        endFields[2].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1393
1394        strideFields[2] = new Text(selectionComposite, SWT.SINGLE | SWT.BORDER);
1395        strideFields[2].setFont(curFont);
1396        strideFields[2].setText("1");
1397        strideFields[2].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1398
1399        maxLabels[2] = new Label(selectionComposite, SWT.NONE);
1400        maxLabels[2].setFont(curFont);
1401        maxLabels[2].setText("1");
1402        maxLabels[2].setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
1403
1404        // Create row for Dims and reset button
1405        new Label(selectionComposite, SWT.RIGHT).setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
1406
1407        Button dimsButton = new Button(selectionComposite, SWT.PUSH);
1408        dimsButton.setFont(curFont);
1409        dimsButton.setText("Dims...");
1410        dimsButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
1411        dimsButton.setEnabled((rank > 3));
1412        dimsButton.addSelectionListener(new SelectionAdapter() {
1413            @Override
1414            public void widgetSelected(SelectionEvent e)
1415            {
1416                if (rank < 4) {
1417                    return;
1418                }
1419
1420                int idx                = 0;
1421                Vector<Object> choice4 = new Vector<>(rank);
1422                int[] choice4Index     = new int[rank - 3];
1423                for (int i = 0; i < rank; i++) {
1424                    if ((i != currentIndex[0]) && (i != currentIndex[1]) && (i != currentIndex[2])) {
1425                        choice4.add(choices[0].getItem(i));
1426                        choice4Index[idx++] = i;
1427                    }
1428                }
1429
1430                String msg = "Select slice location for dimension(s):\n\"" + choice4.get(0) + " [0 .. " +
1431                             (dims[choice4Index[0]] - 1) + "]\"";
1432                String initValue = String.valueOf(start[choice4Index[0]]);
1433                int n            = choice4.size();
1434                for (int i = 1; i < n; i++) {
1435                    msg += " x \"" + choice4.get(i) + " [0 .. " + (dims[choice4Index[i]] - 1) + "]\"";
1436                    initValue += " x " + String.valueOf(start[choice4Index[i]]);
1437                }
1438
1439                String result = new InputDialog(shell, shell.getText(), msg, initValue).open();
1440                if ((result == null) || ((result = result.trim()) == null) || (result.length() < 1)) {
1441                    return;
1442                }
1443
1444                StringTokenizer st = new StringTokenizer(result, "x");
1445                if (st.countTokens() < n) {
1446                    Tools.showError(shell, "Select",
1447                                    "Number of dimension(s) is less than " + n + "\n" + result);
1448                    return;
1449                }
1450
1451                long[] start4 = new long[n];
1452                for (int i = 0; i < n; i++) {
1453                    try {
1454                        start4[i] = Long.parseLong(st.nextToken().trim());
1455                    }
1456                    catch (Exception ex) {
1457                        Tools.showError(shell, "Select", ex.getMessage());
1458                        return;
1459                    }
1460
1461                    if ((start4[i] < 0) || (start4[i] >= dims[choice4Index[i]])) {
1462                        Tools.showError(shell, "Select",
1463                                        "Slice location is out of range.\n" + start4[i] +
1464                                            " >= " + dims[choice4Index[i]]);
1465
1466                        return;
1467                    }
1468                }
1469
1470                for (int i = 0; i < n; i++) {
1471                    start[choice4Index[i]] = start4[i];
1472                }
1473            }
1474        });
1475
1476        new Label(selectionComposite, SWT.RIGHT).setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
1477
1478        new Label(selectionComposite, SWT.RIGHT).setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
1479
1480        Button resetButton = new Button(selectionComposite, SWT.PUSH);
1481        resetButton.setFont(curFont);
1482        resetButton.setText("Reset");
1483        resetButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
1484        resetButton.addSelectionListener(new SelectionAdapter() {
1485            @Override
1486            public void widgetSelected(SelectionEvent e)
1487            {
1488                int n = startFields.length;
1489
1490                for (int i = 0; i < n; i++) {
1491                    startFields[i].setText("0");
1492                    strideFields[i].setText("1");
1493                    long l = Long.valueOf(maxLabels[i].getText()) - 1;
1494                    endFields[i].setText(String.valueOf(l));
1495                }
1496            }
1497        });
1498
1499        new Label(selectionComposite, SWT.RIGHT).setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
1500
1501        for (int i = 0; i < 3; i++) {
1502            // Disable the selection components
1503            // init() will set them appropriately
1504            choices[i].setEnabled(false);
1505            startFields[i].setEnabled(false);
1506            endFields[i].setEnabled(false);
1507            strideFields[i].setEnabled(false);
1508            maxLabels[i].setEnabled(false);
1509        }
1510    }
1511
1512    private void processComboBoxEvent(Combo source)
1513    {
1514        int theSelectedChoice = -1;
1515
1516        int n = Math.min(3, rank);
1517        for (int i = 0; i < n; i++) {
1518            if (source.equals(choices[i])) {
1519                theSelectedChoice = i;
1520            }
1521        }
1522
1523        if (theSelectedChoice < 0) {
1524            return; // the selected ComboBox is not a dimension choice
1525        }
1526
1527        int theIndex = source.getSelectionIndex();
1528        if (theIndex == currentIndex[theSelectedChoice]) {
1529            return; // select the same item, no change
1530        }
1531
1532        start[currentIndex[theSelectedChoice]] = 0;
1533
1534        // reset the selected dimension choice
1535        startFields[theSelectedChoice].setText("0");
1536        endFields[theSelectedChoice].setText(String.valueOf(dims[theIndex] - 1));
1537        strideFields[theSelectedChoice].setText("1");
1538        maxLabels[theSelectedChoice].setText(String.valueOf(dims[theIndex]));
1539
1540        // if the selected choice selects the dimension that is selected by
1541        // other dimension choice, exchange the dimensions
1542        for (int i = 0; i < n; i++) {
1543            if (i == theSelectedChoice) {
1544                continue; // don't exchange itself
1545            }
1546            else if (theIndex == choices[i].getSelectionIndex()) {
1547                choices[i].select(currentIndex[theSelectedChoice]);
1548                startFields[i].setText("0");
1549                endFields[i].setText(String.valueOf(dims[currentIndex[theSelectedChoice]] - 1));
1550                strideFields[i].setText("1");
1551                maxLabels[i].setText(String.valueOf(dims[currentIndex[theSelectedChoice]]));
1552            }
1553        }
1554
1555        for (int i = 0; i < n; i++) {
1556            currentIndex[i] = choices[i].getSelectionIndex();
1557        }
1558
1559        // update the navigator
1560        if (rank > 1) {
1561            int hIdx = choices[0].getSelectionIndex();
1562            int wIdx = choices[1].getSelectionIndex();
1563            transposeChoice.select(0);
1564
1565            // Use transpose option only if the dims are not in original
1566            // order
1567            if (hIdx < wIdx)
1568                transposeChoice.setEnabled(false);
1569            else
1570                transposeChoice.setEnabled(true);
1571
1572            long dims[] = dataObject.getDims();
1573            int w       = (int)dims[wIdx];
1574            int h       = (int)dims[hIdx];
1575
1576            if (navigator != null) {
1577                navigator.setDimensionSize(w, h);
1578                navigator.redraw();
1579            }
1580        }
1581
1582        if (rank > 2) {
1583            endFields[2].setText(startFields[2].getText());
1584        }
1585    }
1586
1587    /**
1588     * PreviewNavigator draws a selection rectangle for selecting a subset
1589     *  of the data to be displayed.
1590     */
1591    private class PreviewNavigator extends Canvas {
1592        private final int NAVIGATOR_SIZE = 150;
1593        private int dimX, dimY, x, y;
1594        private double r;
1595        private Point startPosition; // mouse clicked position
1596        private Rectangle selectedArea;
1597        private Image previewImage = null;
1598        private String selStr;
1599
1600        private PreviewNavigator(Composite parent, int style, int w, int h)
1601        {
1602            super(parent, style);
1603
1604            GridData data   = new GridData(SWT.FILL, SWT.FILL, false, true);
1605            data.widthHint  = NAVIGATOR_SIZE;
1606            data.heightHint = NAVIGATOR_SIZE;
1607            this.setLayoutData(data);
1608
1609            dimX = w;
1610            dimY = h;
1611            if (dimX > dimY) {
1612                x = NAVIGATOR_SIZE;
1613                r = dimX / (double)x;
1614                y = (int)(dimY / r);
1615            }
1616            else {
1617                y = NAVIGATOR_SIZE;
1618                r = dimY / (double)y;
1619                x = (int)(dimX / r);
1620            }
1621
1622            selectedArea = new Rectangle();
1623
1624            selStr = "";
1625
1626            try {
1627                previewImage = createPreviewImage();
1628
1629                String origStr = ViewProperties.getImageOrigin();
1630                if (ViewProperties.ORIGIN_LL.equalsIgnoreCase(origStr))
1631                    flip(DefaultImageView.FLIP_VERTICAL);
1632                else if (ViewProperties.ORIGIN_UR.equalsIgnoreCase(origStr))
1633                    flip(DefaultImageView.FLIP_HORIZONTAL);
1634                else if (ViewProperties.ORIGIN_LR.equalsIgnoreCase(origStr)) {
1635                    rotate(DefaultImageView.ROTATE_CW_90);
1636                    rotate(DefaultImageView.ROTATE_CW_90);
1637                }
1638            }
1639            catch (Exception ex) {
1640                ex.printStackTrace();
1641            }
1642
1643            this.addMouseListener(new MouseListener() {
1644                @Override
1645                public void mouseDoubleClick(MouseEvent e)
1646                {
1647                }
1648
1649                @Override
1650                public void mouseDown(MouseEvent e)
1651                {
1652                    startPosition = new Point(e.x, e.y);
1653                    selectedArea.setBounds(startPosition.x, startPosition.y, 0, 0);
1654                }
1655
1656                @Override
1657                public void mouseUp(MouseEvent e)
1658                {
1659                    if (startPosition.x == e.x && startPosition.y == e.y) {
1660                        selectedArea.setBounds(startPosition.x, startPosition.y, 0, 0);
1661                        redraw();
1662                    }
1663                }
1664            });
1665
1666            this.addMouseMoveListener(new MouseMoveListener() {
1667                @Override
1668                public void mouseMove(MouseEvent e)
1669                {
1670                    if (e.stateMask == SWT.BUTTON1 || e.stateMask == SWT.BUTTON3) {
1671                        Point p0 = startPosition;
1672                        Point p1 = new Point(e.x, e.y);
1673
1674                        int x0 = Math.max(0, Math.min(p0.x, p1.x));
1675                        int y0 = Math.max(0, Math.min(p0.y, p1.y));
1676                        int x1 = Math.min(x, Math.max(p0.x, p1.x));
1677                        int y1 = Math.min(y, Math.max(p0.y, p1.y));
1678
1679                        int w = x1 - x0;
1680                        int h = y1 - y0;
1681
1682                        selectedArea.setBounds(x0, y0, w, h);
1683
1684                        try {
1685                            updateSelection(x0, y0, w, h);
1686                        }
1687                        catch (Exception ex) {
1688                        }
1689
1690                        redraw();
1691                    }
1692                }
1693            });
1694
1695            this.addPaintListener(new PaintListener() {
1696                @Override
1697                public void paintControl(PaintEvent e)
1698                {
1699                    GC gc = e.gc;
1700
1701                    gc.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLUE));
1702
1703                    if (previewImage != null) {
1704                        gc.drawImage(convertBufferedImageToSWTImage((BufferedImage)previewImage), 0, 0);
1705                    }
1706                    else {
1707                        gc.fillRectangle(0, 0, x, y);
1708                    }
1709
1710                    int w = selectedArea.width;
1711                    int h = selectedArea.height;
1712                    if ((w > 0) && (h > 0)) {
1713                        gc.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
1714                        gc.drawRectangle(selectedArea.x, selectedArea.y, w, h);
1715                    }
1716
1717                    org.eclipse.swt.graphics.Rectangle bounds = ((Canvas)e.widget).getBounds();
1718                    Point textSize                            = gc.stringExtent(selStr);
1719                    gc.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
1720                    gc.drawString(selStr, (bounds.width / 2) - (textSize.x / 2),
1721                                  bounds.height - textSize.y - 4);
1722                }
1723            });
1724        }
1725
1726        private Image createPreviewImage() throws Exception
1727        {
1728            if ((rank <= 1) || !(dataObject instanceof ScalarDS)) {
1729                return null;
1730            }
1731
1732            Image preImage = null;
1733            ScalarDS sd    = (ScalarDS)dataObject;
1734
1735            if (sd.getDatatype().isText()) {
1736                return null;
1737            }
1738
1739            // backup the selection
1740            long[] strideBackup       = new long[rank];
1741            long[] selectedBackup     = new long[rank];
1742            long[] startBackup        = new long[rank];
1743            int[] selectedIndexBackup = new int[3];
1744            System.arraycopy(stride, 0, strideBackup, 0, rank);
1745            System.arraycopy(selected, 0, selectedBackup, 0, rank);
1746            System.arraycopy(start, 0, startBackup, 0, rank);
1747            System.arraycopy(selectedIndex, 0, selectedIndexBackup, 0, 3);
1748
1749            // set the selection for preview
1750            for (int i = 0; i < rank; i++) {
1751                start[i]    = 0;
1752                stride[i]   = 1;
1753                selected[i] = 1;
1754            }
1755
1756            if (choices != null) {
1757                try {
1758                    selectedIndex[0] = choices[0].getSelectionIndex();
1759                    selectedIndex[1] = choices[1].getSelectionIndex();
1760                }
1761                catch (Exception ex) {
1762                }
1763            }
1764            long steps                 = (long)Math.ceil(r);
1765            selected[selectedIndex[0]] = (dims[selectedIndex[0]] / steps);
1766            selected[selectedIndex[1]] = (dims[selectedIndex[1]] / steps);
1767            stride[selectedIndex[0]] = stride[selectedIndex[1]] = steps;
1768
1769            if (selected[selectedIndex[0]] == 0) {
1770                selected[selectedIndex[0]] = 1;
1771            }
1772            if (selected[selectedIndex[1]] == 0) {
1773                selected[selectedIndex[1]] = 1;
1774            }
1775
1776            if (isTrueColorImage && (start.length > 2)) {
1777                start[selectedIndex[2]]    = 0;
1778                selected[selectedIndex[2]] = 3;
1779                stride[selectedIndex[2]]   = 1;
1780            }
1781
1782            // update the ratio of preview image size to the real dataset
1783            y = (int)selected[selectedIndex[0]];
1784            x = (int)selected[selectedIndex[1]];
1785            r = Math.min((double)dims[selectedIndex[0]] / (double)selected[selectedIndex[0]],
1786                         (double)dims[selectedIndex[1]] / (double)selected[selectedIndex[1]]);
1787
1788            try {
1789                Object data = sd.read();
1790                int h       = (int)sd.getHeight();
1791                int w       = (int)sd.getWidth();
1792
1793                byte[] bData = Tools.getBytes(data, sd.getImageDataRange(), w, h, false,
1794                                              sd.getFilteredImageValues(), null);
1795
1796                if (isTrueColorImage) {
1797                    boolean isPlaneInterlace = (sd.getInterlace() == ScalarDS.INTERLACE_PLANE);
1798                    preImage                 = Tools.createTrueColorImage(bData, isPlaneInterlace, w, h);
1799                }
1800                else {
1801                    byte[][] imagePalette = sd.getPalette();
1802                    if (imagePalette == null) {
1803                        imagePalette = Tools.createGrayPalette();
1804                    }
1805
1806                    if ((isH5 || (rank > 2)) && (selectedIndex[0] > selectedIndex[1])) {
1807                        // transpose data
1808                        int n         = bData.length;
1809                        byte[] bData2 = new byte[n];
1810                        for (int i = 0; i < h; i++) {
1811                            for (int j = 0; j < w; j++) {
1812                                bData[i * w + j] = bData2[j * h + i];
1813                            }
1814                        }
1815                    }
1816                    if (!isH5 && !sd.isDefaultImageOrder() && (selectedIndex[1] > selectedIndex[0])) {
1817                        // transpose data for hdf4 images where selectedIndex[1]
1818                        // > selectedIndex[0]
1819                        int n         = bData.length;
1820                        byte[] bData2 = new byte[n];
1821                        for (int i = 0; i < h; i++) {
1822                            for (int j = 0; j < w; j++) {
1823                                bData[i * w + j] = bData2[j * h + i];
1824                            }
1825                        }
1826                    }
1827                    preImage = Tools.createIndexedImage(null, bData, imagePalette, w, h);
1828                }
1829            }
1830            finally {
1831                // set back the original selection
1832                System.arraycopy(strideBackup, 0, stride, 0, rank);
1833                System.arraycopy(selectedBackup, 0, selected, 0, rank);
1834                System.arraycopy(startBackup, 0, start, 0, rank);
1835                System.arraycopy(selectedIndexBackup, 0, selectedIndex, 0, 3);
1836            }
1837
1838            return preImage;
1839        }
1840
1841        private void updateSelection(int x0, int y0, int w, int h)
1842        {
1843            int i0 = 0, i1 = 0;
1844
1845            i0 = (int)(y0 * r);
1846            if (i0 > dims[currentIndex[0]]) {
1847                i0 = (int)dims[currentIndex[0]];
1848            }
1849            startFields[0].setText(String.valueOf(i0));
1850
1851            i1 = (int)((y0 + h) * r);
1852
1853            if (i1 < i0) {
1854                i1 = i0;
1855            }
1856            endFields[0].setText(String.valueOf(i1));
1857
1858            selStr = String.valueOf((int)(h * r));
1859
1860            if (rank > 1) {
1861                i0 = (int)(x0 * r);
1862                if (i0 > dims[currentIndex[1]]) {
1863                    i0 = (int)dims[currentIndex[1]];
1864                }
1865                startFields[1].setText(String.valueOf(i0));
1866
1867                i1 = (int)((x0 + w) * r);
1868                if (i1 < i0) {
1869                    i1 = i0;
1870                }
1871                endFields[1].setText(String.valueOf(i1));
1872
1873                selStr += " x " + ((int)(w * r));
1874            }
1875        }
1876
1877        private void setDimensionSize(int w, int h)
1878        {
1879            dimX = w;
1880            dimY = h;
1881            if (dimX > dimY) {
1882                x = NAVIGATOR_SIZE;
1883                r = dimX / (double)x;
1884                y = (int)(dimY / r);
1885            }
1886            else {
1887                y = NAVIGATOR_SIZE;
1888                r = dimY / (double)y;
1889                x = (int)(dimX / r);
1890            }
1891
1892            selectedArea.setSize(0, 0);
1893
1894            try {
1895                previewImage = createPreviewImage();
1896            }
1897            catch (Exception ex) {
1898            }
1899
1900            this.redraw();
1901        }
1902
1903        private boolean applyImageFilter(ImageFilter filter)
1904        {
1905            boolean status              = true;
1906            ImageProducer imageProducer = previewImage.getSource();
1907
1908            try {
1909                previewImage = Tools.toBufferedImage(
1910                    Toolkit.getDefaultToolkit().createImage(new FilteredImageSource(imageProducer, filter)));
1911            }
1912            catch (Exception err) {
1913                shell.getDisplay().beep();
1914                Tools.showError(shell, "Apply Image Filter", err.getMessage());
1915                status = false;
1916            }
1917
1918            return status;
1919        }
1920
1921        private void flip(int direction) { applyImageFilter(new FlipFilter(direction)); }
1922
1923        private void rotate(int direction)
1924        {
1925            if (!(direction == DefaultImageView.ROTATE_CW_90 || direction == DefaultImageView.ROTATE_CCW_90))
1926                return;
1927
1928            applyImageFilter(new Rotate90Filter(direction));
1929        }
1930
1931        /**
1932         * Converts a given BufferedImage to ImageData for a SWT-readable Image
1933         *
1934         * @param image The BufferedImage to be converted
1935         *
1936         * @return the Image
1937         */
1938        private org.eclipse.swt.graphics.Image convertBufferedImageToSWTImage(BufferedImage image)
1939        {
1940            Display display = this.getDisplay();
1941
1942            if (image.getColorModel() instanceof DirectColorModel) {
1943                DirectColorModel colorModel = (DirectColorModel)image.getColorModel();
1944                PaletteData palette = new PaletteData(colorModel.getRedMask(), colorModel.getGreenMask(),
1945                                                      colorModel.getBlueMask());
1946                ImageData data =
1947                    new ImageData(image.getWidth(), image.getHeight(), colorModel.getPixelSize(), palette);
1948
1949                for (int y = 0; y < data.height; y++) {
1950                    for (int x = 0; x < data.width; x++) {
1951                        int rgb = image.getRGB(x, y);
1952                        int pixel =
1953                            palette.getPixel(new RGB((rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF, rgb & 0xFF));
1954                        data.setPixel(x, y, pixel);
1955                        if (colorModel.hasAlpha()) {
1956                            data.setAlpha(x, y, (rgb >> 24) & 0xFF);
1957                        }
1958                    }
1959                }
1960
1961                return new org.eclipse.swt.graphics.Image(display, data);
1962            }
1963            else if (image.getColorModel() instanceof IndexColorModel) {
1964                IndexColorModel colorModel = (IndexColorModel)image.getColorModel();
1965                int size                   = colorModel.getMapSize();
1966                byte[] reds                = new byte[size];
1967                byte[] greens              = new byte[size];
1968                byte[] blues               = new byte[size];
1969                colorModel.getReds(reds);
1970                colorModel.getGreens(greens);
1971                colorModel.getBlues(blues);
1972                RGB[] rgbs = new RGB[size];
1973                for (int i = 0; i < rgbs.length; i++) {
1974                    rgbs[i] = new RGB(reds[i] & 0xFF, greens[i] & 0xFF, blues[i] & 0xFF);
1975                }
1976                PaletteData palette = new PaletteData(rgbs);
1977                ImageData data =
1978                    new ImageData(image.getWidth(), image.getHeight(), colorModel.getPixelSize(), palette);
1979                data.transparentPixel = colorModel.getTransparentPixel();
1980                WritableRaster raster = image.getRaster();
1981                int[] pixelArray      = new int[1];
1982                for (int y = 0; y < data.height; y++) {
1983                    for (int x = 0; x < data.width; x++) {
1984                        raster.getPixel(x, y, pixelArray);
1985                        data.setPixel(x, y, pixelArray[0]);
1986                    }
1987                }
1988
1989                return new org.eclipse.swt.graphics.Image(display, data);
1990            }
1991            else if (image.getColorModel() instanceof ComponentColorModel) {
1992                ComponentColorModel colorModel = (ComponentColorModel)image.getColorModel();
1993                // ASSUMES: 3 BYTE BGR IMAGE TYPE
1994                PaletteData palette = new PaletteData(0x0000FF, 0x00FF00, 0xFF0000);
1995                ImageData data =
1996                    new ImageData(image.getWidth(), image.getHeight(), colorModel.getPixelSize(), palette);
1997                // This is valid because we are using a 3-byte Data model with no transparent pixels
1998                data.transparentPixel = -1;
1999                WritableRaster raster = image.getRaster();
2000                int[] pixelArray      = new int[3];
2001                for (int y = 0; y < data.height; y++) {
2002                    for (int x = 0; x < data.width; x++) {
2003                        raster.getPixel(x, y, pixelArray);
2004                        int pixel = palette.getPixel(new RGB(pixelArray[0], pixelArray[1], pixelArray[2]));
2005                        data.setPixel(x, y, pixel);
2006                    }
2007                }
2008                return new org.eclipse.swt.graphics.Image(display, data);
2009            }
2010
2011            return null;
2012        }
2013    }
2014}