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.io.InputStream;
018import java.net.URL;
019import java.net.URLClassLoader;
020import java.util.Iterator;
021import java.util.List;
022import java.util.Scanner;
023import java.util.StringTokenizer;
024import java.util.Vector;
025
026import hdf.object.Dataset;
027import hdf.object.Datatype;
028import hdf.object.Group;
029import hdf.object.HObject;
030import hdf.object.ScalarDS;
031import hdf.view.DataView.DataView;
032import hdf.view.ImageView.ImageView;
033import hdf.view.TableView.TableView;
034import hdf.view.Tools;
035import hdf.view.ViewProperties;
036
037import org.slf4j.Logger;
038import org.slf4j.LoggerFactory;
039
040import org.eclipse.swt.SWT;
041import org.eclipse.swt.browser.Browser;
042import org.eclipse.swt.events.DisposeEvent;
043import org.eclipse.swt.events.DisposeListener;
044import org.eclipse.swt.events.SelectionAdapter;
045import org.eclipse.swt.events.SelectionEvent;
046import org.eclipse.swt.graphics.Point;
047import org.eclipse.swt.graphics.Rectangle;
048import org.eclipse.swt.layout.GridData;
049import org.eclipse.swt.layout.GridLayout;
050import org.eclipse.swt.widgets.Button;
051import org.eclipse.swt.widgets.Combo;
052import org.eclipse.swt.widgets.Composite;
053import org.eclipse.swt.widgets.Dialog;
054import org.eclipse.swt.widgets.Display;
055import org.eclipse.swt.widgets.Label;
056import org.eclipse.swt.widgets.Shell;
057import org.eclipse.swt.widgets.Text;
058
059/**
060 * NewDatasetDialog shows a message dialog requesting user input for creating a
061 * new HDF4/5 dataset.
062 *
063 * @author Jordan T. Henderson
064 * @version 2.4 12/31/2015
065 */
066public class NewDatasetDialog extends NewDataObjectDialog {
067
068    private static final Logger log = LoggerFactory.getLogger(NewDatasetDialog.class);
069
070    private String maxSize;
071
072    private Text currentSizeField, chunkSizeField, fillValueField;
073
074    private Combo parentChoice, rankChoice, compressionLevel;
075
076    private Button checkCompression, checkFillValue;
077
078    private Button checkContiguous, checkChunked;
079
080    /** TextField for entering the name of the object */
081    protected Text nameField;
082
083    /** A list of current groups */
084    private List<Group> groupList;
085
086    private final DataView dataView;
087
088    /**
089     * Constructs a NewDatasetDialog with specified list of possible parent
090     * groups.
091     *
092     * @param parent
093     *            the parent shell of the dialog
094     * @param pGroup
095     *            the parent group which the new group is added to.
096     * @param objs
097     *            the list of all objects.
098     */
099    public NewDatasetDialog(Shell parent, Group pGroup, List<?> objs)
100    {
101        super(parent, pGroup, objs);
102
103        dataView = null;
104    }
105
106    /**
107     * Constructs a NewDatasetDialog with specified list of possible parent
108     * groups.
109     *
110     * @param parent
111     *            the parent shell of the dialog
112     * @param pGroup
113     *            the parent group which the new group is added to.
114     * @param objs
115     *            the list of all objects.
116     * @param observer
117     *            the Dataview attached to this dialog.
118     */
119    public NewDatasetDialog(Shell parent, Group pGroup, List<?> objs, DataView observer)
120    {
121        super(parent, pGroup, objs);
122
123        dataView = observer;
124    }
125
126    /**
127     * Open the NewDataseteDialog for adding a new dataset.
128     */
129    public void open()
130    {
131        Shell parent = getParent();
132        shell        = new Shell(parent, SWT.SHELL_TRIM | SWT.APPLICATION_MODAL);
133        shell.setFont(curFont);
134        shell.setText("New Dataset...");
135        shell.setImages(ViewProperties.getHdfIcons());
136        shell.setLayout(new GridLayout(1, true));
137
138        // Create Dataset name / Parent Group region
139        Composite fieldComposite = new Composite(shell, SWT.NONE);
140        fieldComposite.setLayout(new GridLayout(2, false));
141        fieldComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
142
143        Label datasetNameLabel = new Label(fieldComposite, SWT.LEFT);
144        datasetNameLabel.setFont(curFont);
145        datasetNameLabel.setText("Dataset name: ");
146
147        nameField = new Text(fieldComposite, SWT.SINGLE | SWT.BORDER);
148        nameField.setFont(curFont);
149        GridData data = new GridData(SWT.FILL, SWT.FILL, true, false);
150
151        data.minimumWidth = 250;
152        nameField.setLayoutData(data);
153
154        Label parentGroupLabel = new Label(fieldComposite, SWT.LEFT);
155        parentGroupLabel.setFont(curFont);
156        parentGroupLabel.setText("Parent group: ");
157
158        parentChoice = new Combo(fieldComposite, SWT.DROP_DOWN | SWT.BORDER | SWT.READ_ONLY);
159        parentChoice.setFont(curFont);
160        parentChoice.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
161        parentChoice.addSelectionListener(new SelectionAdapter() {
162            @Override
163            public void widgetSelected(SelectionEvent e)
164            {
165                parentObj = groupList.get(parentChoice.getSelectionIndex());
166            }
167        });
168
169        groupList            = new Vector<>();
170        Object obj           = null;
171        Iterator<?> iterator = objList.iterator();
172
173        while (iterator.hasNext()) {
174            obj = iterator.next();
175            if (obj instanceof Group) {
176                Group g = (Group)obj;
177                groupList.add(g);
178                if (g.isRoot()) {
179                    parentChoice.add(HObject.SEPARATOR);
180                }
181                else {
182                    parentChoice.add(g.getPath() + g.getName() + HObject.SEPARATOR);
183                }
184            }
185        }
186
187        if (((Group)parentObj).isRoot()) {
188            parentChoice.select(parentChoice.indexOf(HObject.SEPARATOR));
189        }
190        else {
191            parentChoice.select(
192                parentChoice.indexOf(parentObj.getPath() + parentObj.getName() + HObject.SEPARATOR));
193        }
194
195        // Create New Dataset from scratch
196        if (dataView == null) {
197            // Create Datatype region
198            createDatatypeWidget();
199
200            // Create Dataspace region
201            org.eclipse.swt.widgets.Group dataspaceGroup = new org.eclipse.swt.widgets.Group(shell, SWT.NONE);
202            dataspaceGroup.setFont(curFont);
203            dataspaceGroup.setText("Dataspace");
204            dataspaceGroup.setLayout(new GridLayout(3, true));
205            dataspaceGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
206
207            Label label = new Label(dataspaceGroup, SWT.LEFT);
208            label.setFont(curFont);
209            label.setText("No. of dimensions");
210
211            label = new Label(dataspaceGroup, SWT.LEFT);
212            label.setFont(curFont);
213            label.setText("Current size");
214
215            // Dummy label
216            label = new Label(dataspaceGroup, SWT.LEFT);
217            label.setFont(curFont);
218            label.setText("");
219
220            rankChoice = new Combo(dataspaceGroup, SWT.DROP_DOWN | SWT.READ_ONLY);
221            rankChoice.setFont(curFont);
222            rankChoice.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
223            rankChoice.addSelectionListener(new SelectionAdapter() {
224                @Override
225                public void widgetSelected(SelectionEvent e)
226                {
227                    int rank                     = rankChoice.getSelectionIndex() + 1;
228                    StringBuilder currentSizeStr = new StringBuilder("1");
229
230                    for (int i = 1; i < rank; i++) {
231                        currentSizeStr.append(" x 1");
232                    }
233
234                    currentSizeField.setText(currentSizeStr.toString());
235
236                    String currentStr = currentSizeField.getText();
237                    int idx           = currentStr.lastIndexOf('x');
238
239                    StringBuilder chunkStr = new StringBuilder();
240
241                    if (rank <= 1) {
242                        chunkStr.append(currentStr);
243                    }
244                    else {
245                        chunkStr.append("1");
246                        for (int i = 1; i < rank - 1; i++) {
247                            chunkStr.append(" x 1");
248                        }
249                        if (idx > 0) {
250                            chunkStr.append(" x ");
251                            chunkStr.append(currentStr.substring(idx + 1));
252                        }
253                    }
254
255                    chunkSizeField.setText(chunkStr.toString());
256                }
257            });
258
259            for (int i = 1; i < 33; i++) {
260                rankChoice.add(String.valueOf(i));
261            }
262            rankChoice.select(1);
263
264            currentSizeField = new Text(dataspaceGroup, SWT.SINGLE | SWT.BORDER);
265            currentSizeField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
266            currentSizeField.setFont(curFont);
267            currentSizeField.setText("1 x 1");
268
269            Button setMaxSizeButton = new Button(dataspaceGroup, SWT.PUSH);
270            setMaxSizeButton.setFont(curFont);
271            setMaxSizeButton.setText("Set Max Size");
272            setMaxSizeButton.setLayoutData(new GridData(SWT.END, SWT.FILL, false, false));
273            setMaxSizeButton.addSelectionListener(new SelectionAdapter() {
274                @Override
275                public void widgetSelected(SelectionEvent e)
276                {
277                    if (maxSize == null || maxSize.length() < 1)
278                        maxSize = currentSizeField.getText();
279
280                    String msg = new InputDialog(shell, "Set Max Size",
281                                                 "Enter max dimension sizes. \n"
282                                                     + "Use \"unlimited\" for unlimited dimension size.\n\n"
283                                                     + "For example,\n"
284                                                     + "    200 x 100\n"
285                                                     + "    100 x unlimited\n\n",
286                                                 maxSize)
287                                     .open();
288
289                    if (msg == null || msg.length() < 1)
290                        maxSize = currentSizeField.getText();
291                    else
292                        maxSize = msg;
293
294                    checkMaxSize();
295                }
296            });
297
298            // Create Storage Properties region
299            org.eclipse.swt.widgets.Group storagePropertiesGroup =
300                new org.eclipse.swt.widgets.Group(shell, SWT.NONE);
301            storagePropertiesGroup.setFont(curFont);
302            storagePropertiesGroup.setText("Storage Properties");
303            storagePropertiesGroup.setLayout(new GridLayout(5, true));
304            storagePropertiesGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
305
306            label = new Label(storagePropertiesGroup, SWT.LEFT);
307            label.setFont(curFont);
308            label.setText("Storage layout: ");
309
310            checkContiguous = new Button(storagePropertiesGroup, SWT.RADIO);
311            checkContiguous.setFont(curFont);
312            checkContiguous.setText("Contiguous");
313            checkContiguous.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
314            checkContiguous.setSelection(true);
315            checkContiguous.addSelectionListener(new SelectionAdapter() {
316                @Override
317                public void widgetSelected(SelectionEvent e)
318                {
319                    chunkSizeField.setEnabled(false);
320                }
321            });
322
323            // Dummy label
324            label = new Label(storagePropertiesGroup, SWT.LEFT);
325            label.setFont(curFont);
326            label.setText("");
327            label.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
328
329            checkChunked = new Button(storagePropertiesGroup, SWT.RADIO);
330            checkChunked.setFont(curFont);
331            checkChunked.setText("Chunked (size) ");
332            checkChunked.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
333            checkChunked.addSelectionListener(new SelectionAdapter() {
334                @Override
335                public void widgetSelected(SelectionEvent e)
336                {
337                    chunkSizeField.setEnabled(true);
338                    StringBuilder chunkStr = new StringBuilder();
339                    StringTokenizer st     = new StringTokenizer(currentSizeField.getText(), "x");
340                    int rank               = rankChoice.getSelectionIndex() + 1;
341                    while (st.hasMoreTokens()) {
342                        long l = Math.max(1, Long.valueOf(st.nextToken().trim()) / (2 * rank));
343                        chunkStr.append(String.valueOf(l));
344                        chunkStr.append("x");
345                    }
346                    String chunkString = chunkStr.substring(0, chunkStr.lastIndexOf("x"));
347                    chunkSizeField.setText(chunkString);
348                }
349            });
350
351            chunkSizeField = new Text(storagePropertiesGroup, SWT.SINGLE | SWT.BORDER);
352            chunkSizeField.setFont(curFont);
353            chunkSizeField.setText("1 x 1");
354            chunkSizeField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
355            chunkSizeField.setEnabled(false);
356
357            label = new Label(storagePropertiesGroup, SWT.LEFT);
358            label.setFont(curFont);
359            label.setText("Compression: ");
360
361            checkCompression = new Button(storagePropertiesGroup, SWT.CHECK);
362            checkCompression.setFont(curFont);
363            checkCompression.setText("gzip (level) ");
364            checkCompression.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
365            checkCompression.addSelectionListener(new SelectionAdapter() {
366                @Override
367                public void widgetSelected(SelectionEvent e)
368                {
369                    boolean isCompressed = checkCompression.getSelection();
370
371                    if (isCompressed && isH5) {
372                        if (!checkChunked.getSelection()) {
373                            int rank               = rankChoice.getSelectionIndex() + 1;
374                            String currentStr      = currentSizeField.getText();
375                            int idx                = currentStr.lastIndexOf('x');
376                            StringBuilder chunkStr = new StringBuilder();
377
378                            if (rank <= 1) {
379                                chunkStr.append(currentStr);
380                            }
381                            else {
382                                chunkStr.append("1");
383                                for (int i = 1; i < rank - 1; i++) {
384                                    chunkStr.append(" x 1");
385                                }
386                                if (idx > 0) {
387                                    chunkStr.append(" x ");
388                                    chunkStr.append(currentStr.substring(idx + 1));
389                                }
390                            }
391
392                            chunkSizeField.setText(chunkStr.toString());
393                        }
394                        compressionLevel.setEnabled(true);
395                        checkContiguous.setEnabled(false);
396                        checkContiguous.setSelection(false);
397                        checkChunked.setSelection(true);
398                        chunkSizeField.setEnabled(true);
399                    }
400                    else {
401                        compressionLevel.setEnabled(isCompressed);
402                        checkContiguous.setEnabled(true);
403                    }
404                }
405            });
406
407            compressionLevel = new Combo(storagePropertiesGroup, SWT.DROP_DOWN | SWT.READ_ONLY);
408            compressionLevel.setFont(curFont);
409            compressionLevel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
410
411            for (int i = 0; i < 10; i++) {
412                compressionLevel.add(String.valueOf(i));
413            }
414            compressionLevel.select(6);
415            compressionLevel.setEnabled(false);
416
417            if (isH5) {
418                checkFillValue = new Button(storagePropertiesGroup, SWT.CHECK);
419                checkFillValue.setFont(curFont);
420                checkFillValue.setText("Fill Value");
421                checkFillValue.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false));
422                checkFillValue.setSelection(false);
423                checkFillValue.addSelectionListener(new SelectionAdapter() {
424                    @Override
425                    public void widgetSelected(SelectionEvent e)
426                    {
427                        fillValueField.setEnabled(checkFillValue.getSelection());
428                    }
429                });
430
431                fillValueField = new Text(storagePropertiesGroup, SWT.SINGLE | SWT.BORDER);
432                fillValueField.setFont(curFont);
433                fillValueField.setText("0");
434                fillValueField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
435                fillValueField.setEnabled(false);
436            }
437            else {
438                // Add two dummy labels
439                label = new Label(storagePropertiesGroup, SWT.LEFT);
440                label.setFont(curFont);
441                label.setText("");
442                label.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
443
444                label = new Label(storagePropertiesGroup, SWT.LEFT);
445                label.setFont(curFont);
446                label.setText("");
447                label.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
448            }
449        }
450
451        // Create Ok/Cancel/Help button region
452        Composite buttonComposite = new Composite(shell, SWT.NONE);
453        buttonComposite.setLayout(new GridLayout((dataView == null) ? 3 : 2, false));
454        buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
455
456        Button okButton = new Button(buttonComposite, SWT.PUSH);
457        okButton.setFont(curFont);
458        okButton.setText("   &OK   ");
459        okButton.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
460        okButton.addSelectionListener(new SelectionAdapter() {
461            @Override
462            public void widgetSelected(SelectionEvent e)
463            {
464                if (dataView instanceof TableView) {
465                    newObject = createFromTable();
466                }
467                else if (dataView instanceof ImageView) {
468                    newObject = createFromImage();
469                }
470                else if (dataView == null) {
471                    newObject = createFromScratch();
472                }
473
474                if (newObject != null) {
475                    shell.dispose();
476                }
477            }
478        });
479
480        Button cancelButton = new Button(buttonComposite, SWT.PUSH);
481        cancelButton.setFont(curFont);
482        cancelButton.setText(" &Cancel ");
483        cancelButton.setLayoutData(new GridData((dataView == null) ? SWT.CENTER : SWT.BEGINNING, SWT.FILL,
484                                                (dataView == null) ? false : true, false));
485        cancelButton.addSelectionListener(new SelectionAdapter() {
486            @Override
487            public void widgetSelected(SelectionEvent e)
488            {
489                newObject = null;
490                shell.dispose();
491                ((Vector<Group>)groupList).setSize(0);
492            }
493        });
494
495        if (dataView == null) {
496            Button helpButton = new Button(buttonComposite, SWT.PUSH);
497            helpButton.setFont(curFont);
498            helpButton.setText(" &Help ");
499            helpButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, true, false));
500            helpButton.addSelectionListener(new SelectionAdapter() {
501                @Override
502                public void widgetSelected(SelectionEvent e)
503                {
504                    new HelpDialog(shell).open();
505                }
506            });
507        }
508
509        shell.pack();
510
511        shell.addDisposeListener(new DisposeListener() {
512            @Override
513            public void widgetDisposed(DisposeEvent e)
514            {
515                if (curFont != null)
516                    curFont.dispose();
517            }
518        });
519
520        shell.setMinimumSize(shell.computeSize(SWT.DEFAULT, SWT.DEFAULT));
521
522        Rectangle parentBounds = parent.getBounds();
523        Point shellSize        = shell.getSize();
524        shell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2),
525                          (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2));
526
527        shell.open();
528
529        Display display = shell.getDisplay();
530        while (!shell.isDisposed())
531            if (!display.readAndDispatch())
532                display.sleep();
533    }
534
535    /** Check if the max size is valid */
536    private void checkMaxSize()
537    {
538        boolean isChunkNeeded = false;
539        String dimStr         = currentSizeField.getText();
540        String maxSizeStr     = maxSize;
541        StringTokenizer stMax = new StringTokenizer(maxSizeStr, "x");
542        StringTokenizer stDim = new StringTokenizer(dimStr, "x");
543
544        if (stMax.countTokens() != stDim.countTokens()) {
545            shell.getDisplay().beep();
546            Tools.showError(shell, "Check", "Wrong number of values in the max dimension size " + maxSize);
547            maxSize = null;
548            return;
549        }
550
551        int rank = stDim.countTokens();
552        long max = 0, dim = 0;
553        long[] maxdims = new long[rank];
554        for (int i = 0; i < rank; i++) {
555            String token = stMax.nextToken().trim();
556
557            token = token.toLowerCase();
558            if (token.startsWith("u")) {
559                max           = -1;
560                isChunkNeeded = true;
561            }
562            else {
563                try {
564                    max = Long.parseLong(token);
565                }
566                catch (NumberFormatException ex) {
567                    shell.getDisplay().beep();
568                    Tools.showError(shell, "Check", "Invalid max dimension size: " + maxSize);
569                    maxSize = null;
570                    return;
571                }
572            }
573
574            token = stDim.nextToken().trim();
575            try {
576                dim = Long.parseLong(token);
577            }
578            catch (NumberFormatException ex) {
579                shell.getDisplay().beep();
580                Tools.showError(shell, "Check", "Invalid dimension size: " + dimStr);
581                return;
582            }
583
584            if (max != -1 && max < dim) {
585                shell.getDisplay().beep();
586                Tools.showError(shell, "Check", "Invalid max dimension size: " + maxSize);
587                maxSize = null;
588                return;
589            }
590            else if (max > dim) {
591                isChunkNeeded = true;
592            }
593
594            maxdims[i] = max;
595        } //  (int i = 0; i < rank; i++)
596
597        if (isH5) {
598            if (isChunkNeeded && !checkChunked.getSelection()) {
599                shell.getDisplay().beep();
600                Tools.showError(shell, "Check", "Chunking is required for the max dimensions of " + maxSize);
601                checkChunked.setSelection(true);
602            }
603        }
604        else {
605            for (int i = 1; i < rank; i++) {
606                if (maxdims[i] <= 0) {
607                    maxSize = currentSizeField.getText();
608                    shell.getDisplay().beep();
609                    Tools.showError(shell, "Check", "Only dim[0] can be unlimited." + maxSize);
610                    return;
611                }
612            }
613        }
614    }
615
616    private HObject createFromScratch()
617    {
618        String name  = null;
619        Group pgroup = null;
620        int rank     = -1;
621        int gzip     = -1;
622        long[] dims;
623        long[] maxdims = null;
624        long[] chunks  = null;
625
626        name = nameField.getText().trim();
627        if ((name == null) || (name.length() < 1)) {
628            shell.getDisplay().beep();
629            Tools.showError(shell, "Create", "Dataset name is not specified.");
630            return null;
631        }
632
633        if (name.indexOf(HObject.SEPARATOR) >= 0) {
634            shell.getDisplay().beep();
635            Tools.showError(shell, "Create", "Dataset name cannot contain path.");
636            return null;
637        }
638
639        pgroup = groupList.get(parentChoice.getSelectionIndex());
640
641        if (pgroup == null) {
642            shell.getDisplay().beep();
643            Tools.showError(shell, "Create", "Parent group is null.");
644            return null;
645        }
646
647        rank               = rankChoice.getSelectionIndex() + 1;
648        StringTokenizer st = new StringTokenizer(currentSizeField.getText(), "x");
649        if (st.countTokens() < rank) {
650            shell.getDisplay().beep();
651            Tools.showError(shell, "Create",
652                            "Number of values in the current dimension size is less than " + rank);
653            return null;
654        }
655
656        long l       = 0;
657        dims         = new long[rank];
658        String token = null;
659        for (int i = 0; i < rank; i++) {
660            token = st.nextToken().trim();
661            try {
662                l = Long.parseLong(token);
663            }
664            catch (NumberFormatException ex) {
665                shell.getDisplay().beep();
666                Tools.showError(shell, "Create", "Invalid dimension size: " + currentSizeField.getText());
667                return null;
668            }
669
670            if (l <= 0) {
671                shell.getDisplay().beep();
672                Tools.showError(shell, "Create", "Dimension size must be greater than zero.");
673                return null;
674            }
675
676            dims[i] = l;
677        }
678
679        String maxSizeStr = maxSize;
680        if (maxSizeStr != null && maxSizeStr.length() > 1) {
681            st = new StringTokenizer(maxSizeStr, "x");
682            if (st.countTokens() < rank) {
683                shell.getDisplay().beep();
684                Tools.showError(shell, "Create",
685                                "Number of values in the max dimension size is less than " + rank);
686                return null;
687            }
688
689            l       = 0;
690            maxdims = new long[rank];
691            for (int i = 0; i < rank; i++) {
692                token = st.nextToken().trim();
693
694                token = token.toLowerCase();
695                if (token.startsWith("u"))
696                    l = -1;
697                else {
698                    try {
699                        l = Long.parseLong(token);
700                    }
701                    catch (NumberFormatException ex) {
702                        shell.getDisplay().beep();
703                        Tools.showError(shell, "Create", "Invalid max dimension size: " + maxSize);
704                        return null;
705                    }
706                }
707
708                if (l < -1) {
709                    shell.getDisplay().beep();
710                    Tools.showError(shell, "Create", "Dimension size cannot be less than -1.");
711                    return null;
712                }
713                else if (l == 0) {
714                    l = dims[i];
715                }
716
717                maxdims[i] = l;
718            }
719        }
720
721        chunks = null;
722        if (checkChunked.getSelection()) {
723            st = new StringTokenizer(chunkSizeField.getText(), "x");
724            if (st.countTokens() < rank) {
725                shell.getDisplay().beep();
726                Tools.showError(shell, "Create", "Number of values in the chunk size is less than " + rank);
727                return null;
728            }
729
730            l      = 0;
731            chunks = new long[rank];
732            for (int i = 0; i < rank; i++) {
733                token = st.nextToken().trim();
734                try {
735                    l = Long.parseLong(token);
736                }
737                catch (NumberFormatException ex) {
738                    shell.getDisplay().beep();
739                    Tools.showError(shell, "Create",
740                                    "Invalid chunk dimension size: " + chunkSizeField.getText());
741                    return null;
742                }
743
744                if (l < 1) {
745                    shell.getDisplay().beep();
746                    Tools.showError(shell, "Create", "Chunk size cannot be less than 1.");
747                    return null;
748                }
749
750                chunks[i] = l;
751            } //  (int i=0; i<rank; i++)
752
753            long tchunksize = 1;
754            long tdimsize   = 1;
755            for (int i = 0; i < rank; i++) {
756                tchunksize *= chunks[i];
757                tdimsize *= dims[i];
758            }
759
760            if (tchunksize >= tdimsize) {
761                shell.getDisplay().beep();
762                if (!Tools.showConfirm(shell, "Create",
763                                       "Chunk size is equal/greater than the current size. "
764                                           + "\nAre you sure you want to set chunk size to " +
765                                           chunkSizeField.getText() + "?")) {
766                    return null;
767                }
768            }
769
770            if (tchunksize == 1) {
771                shell.getDisplay().beep();
772                if (!Tools.showConfirm(
773                        shell, "Create",
774                        "Chunk size is one, which may cause large memory overhead for large dataset."
775                            + "\nAre you sure you want to set chunk size to " + chunkSizeField.getText() +
776                            "?")) {
777                    return null;
778                }
779            }
780        } //  (checkChunked.isSelected())
781
782        if (checkCompression.getSelection()) {
783            gzip = compressionLevel.getSelectionIndex();
784        }
785        else {
786            gzip = 0;
787        }
788
789        HObject obj = null;
790        try {
791            Datatype datatype = createNewDatatype(null);
792
793            String fillValue = null;
794
795            if (fillValueField != null) {
796                if (fillValueField.isEnabled())
797                    fillValue = fillValueField.getText();
798            }
799
800            obj = fileFormat.createScalarDS(name, pgroup, datatype, dims, maxdims, chunks, gzip, fillValue,
801                                            null);
802        }
803        catch (Exception ex) {
804            shell.getDisplay().beep();
805            Tools.showError(shell, "Create", ex.getMessage());
806            return null;
807        }
808
809        return obj;
810    }
811
812    private HObject createFromTable()
813    {
814        HObject obj = null;
815
816        String name  = null;
817        Group pgroup = null;
818
819        name = nameField.getText();
820        if (name == null || name.length() == 0) {
821            shell.getDisplay().beep();
822            Tools.showError(shell, "Create", "Dataset name is not specified.");
823            return null;
824        }
825
826        if (name.indexOf(HObject.SEPARATOR) >= 0) {
827            shell.getDisplay().beep();
828            Tools.showError(shell, "Create", "Dataset name cannot contain path.");
829            return null;
830        }
831
832        pgroup = groupList.get(parentChoice.getSelectionIndex());
833        if (pgroup == null) {
834            shell.getDisplay().beep();
835            Tools.showError(shell, "Create", "Parent group is null.");
836            return null;
837        }
838
839        TableView tableView = (TableView)dataView;
840        Object theData      = tableView.getSelectedData();
841        if (theData == null) {
842            return null;
843        }
844
845        int w           = tableView.getSelectedColumnCount();
846        int h           = tableView.getSelectedRowCount();
847        Dataset dataset = (Dataset)tableView.getDataObject();
848        if (dataset instanceof ScalarDS) {
849            ScalarDS sd = (ScalarDS)dataset;
850            if (sd.getDatatype().isUnsigned()) {
851                theData = Dataset.convertToUnsignedC(theData, null);
852            }
853        }
854
855        try {
856            long[] dims = {h, w};
857            obj         = dataset.copy(pgroup, name, dims, theData);
858        }
859        catch (Exception ex) {
860            shell.getDisplay().beep();
861            Tools.showError(shell, "Create", ex.getMessage());
862            return null;
863        }
864
865        return obj;
866    }
867
868    private HObject createFromImage()
869    {
870        HObject obj  = null;
871        String name  = null;
872        Group pgroup = null;
873
874        name = nameField.getText();
875        if (name == null || name.length() == 0) {
876            shell.getDisplay().beep();
877            Tools.showError(shell, "Create", "Dataset name is not specified.");
878            return null;
879        }
880
881        if (name.indexOf(HObject.SEPARATOR) >= 0) {
882            shell.getDisplay().beep();
883            Tools.showError(shell, "Create", "Dataset name cannot contain path.");
884            return null;
885        }
886
887        pgroup = groupList.get(parentChoice.getSelectionIndex());
888        if (pgroup == null) {
889            shell.getDisplay().beep();
890            Tools.showError(shell, "Create", "Parent group is null.");
891            return null;
892        }
893
894        ImageView imageView = (ImageView)dataView;
895        ScalarDS dataset    = (ScalarDS)imageView.getDataObject();
896        Object theData      = imageView.getSelectedData();
897
898        if (theData == null) {
899            return null;
900        }
901
902        // in version 2.4, unsigned image data is converted to signed data
903        // to write data, the data needs to be converted back to unsigned.
904        if (dataset.getDatatype().isUnsigned()) {
905            theData = Dataset.convertToUnsignedC(theData, null);
906        }
907
908        int w = imageView.getSelectedArea().width;
909        int h = imageView.getSelectedArea().height;
910
911        try {
912            long[] dims = null;
913            if (isH5) {
914                if (imageView.isTrueColor()) {
915                    dims = new long[3];
916                    if (imageView.isPlaneInterlace()) {
917                        dims[0] = 3;
918                        dims[1] = h;
919                        dims[2] = w;
920                    }
921                    else {
922                        dims[0] = h;
923                        dims[1] = w;
924                        dims[2] = 3;
925                    }
926                }
927                else {
928                    dims    = new long[2];
929                    dims[0] = h;
930                    dims[1] = w;
931                }
932            }
933            else {
934                dims    = new long[2];
935                dims[0] = w;
936                dims[1] = h;
937            }
938
939            obj = dataset.copy(pgroup, name, dims, theData);
940        }
941        catch (Exception ex) {
942            shell.getDisplay().beep();
943            Tools.showError(shell, "Create", ex.getMessage());
944            return null;
945        }
946
947        return obj;
948    }
949
950    private class HelpDialog extends Dialog {
951        private Shell helpShell;
952
953        public HelpDialog(Shell parent) { super(parent, SWT.APPLICATION_MODAL); }
954
955        public void open()
956        {
957            Shell parent = getParent();
958            helpShell =
959                new Shell(parent, SWT.TITLE | SWT.CLOSE | SWT.RESIZE | SWT.BORDER | SWT.APPLICATION_MODAL);
960            helpShell.setFont(curFont);
961            helpShell.setText("Create New Dataset");
962            helpShell.setImages(ViewProperties.getHdfIcons());
963            helpShell.setLayout(new GridLayout(1, true));
964
965            // Try to create a Browser on platforms that support it
966            try {
967                Browser browser = new Browser(helpShell, SWT.NONE);
968                browser.setFont(curFont);
969                browser.setBounds(0, 0, 500, 500);
970                browser.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
971
972                if (ClassLoader.getSystemResource("hdf/view/HDFView.class").toString().startsWith("jar")) {
973                    // Attempt to load HTML help file from jar
974                    try (InputStream in = getClass().getClassLoader().getResourceAsStream(
975                             "hdf/view/NewDatasetHelp.html")) {
976                        Scanner scan         = new Scanner(in);
977                        StringBuilder buffer = new StringBuilder();
978                        while (scan.hasNextLine()) {
979                            buffer.append(scan.nextLine());
980                        }
981
982                        browser.setText(buffer.toString());
983
984                        scan.close();
985                    }
986                    catch (Exception e) {
987                        StringBuilder buff = new StringBuilder();
988                        buff.append("<html>")
989                            .append("<body>")
990                            .append("ERROR: cannot load help information.")
991                            .append("</body>")
992                            .append("</html>");
993                        browser.setText(buff.toString(), true);
994                    }
995                }
996                else {
997                    try {
998                        URL url = null, url2 = null, url3 = null;
999                        String rootPath = ViewProperties.getViewRoot();
1000
1001                        try {
1002                            url = new URL("file://" + rootPath + "/HDFView.jar");
1003                        }
1004                        catch (java.net.MalformedURLException mfu) {
1005                            log.debug("help information:", mfu);
1006                        }
1007
1008                        try {
1009                            url2 = new URL("file://" + rootPath + "/");
1010                        }
1011                        catch (java.net.MalformedURLException mfu) {
1012                            log.debug("help information:", mfu);
1013                        }
1014
1015                        try {
1016                            url3 = new URL("file://" + rootPath + "/src/");
1017                        }
1018                        catch (java.net.MalformedURLException mfu) {
1019                            log.debug("help information:", mfu);
1020                        }
1021
1022                        URL uu[] = {url, url2, url3};
1023                        try (URLClassLoader cl = new URLClassLoader(uu)) {
1024                            URL u = cl.findResource("hdf/view/NewDatasetHelp.html");
1025
1026                            browser.setUrl(u.toString());
1027                        }
1028                        catch (Exception ex) {
1029                            log.trace("URLClassLoader failed:", ex);
1030                        }
1031                    }
1032                    catch (Exception e) {
1033                        StringBuilder buff = new StringBuilder();
1034                        buff.append("<html>")
1035                            .append("<body>")
1036                            .append("ERROR: cannot load help information.")
1037                            .append("</body>")
1038                            .append("</html>");
1039                        browser.setText(buff.toString(), true);
1040                    }
1041                }
1042
1043                Button okButton = new Button(helpShell, SWT.PUSH);
1044                okButton.setFont(curFont);
1045                okButton.setText("   &OK   ");
1046                okButton.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, true, false));
1047                okButton.addSelectionListener(new SelectionAdapter() {
1048                    @Override
1049                    public void widgetSelected(SelectionEvent e)
1050                    {
1051                        helpShell.dispose();
1052                    }
1053                });
1054
1055                helpShell.pack();
1056
1057                helpShell.setSize(new Point(500, 500));
1058
1059                Rectangle parentBounds = parent.getBounds();
1060                Point shellSize        = helpShell.getSize();
1061                helpShell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2),
1062                                      (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2));
1063
1064                helpShell.open();
1065
1066                Display display = parent.getDisplay();
1067                while (!helpShell.isDisposed()) {
1068                    if (!display.readAndDispatch())
1069                        display.sleep();
1070                }
1071            }
1072            catch (Error er) {
1073                // Try opening help link in external browser if platform
1074                // doesn't support SWT browser
1075                Tools.showError(shell, "Browser support",
1076                                "Platform doesn't support Browser. Opening external link in web browser...");
1077
1078                // TODO: Add support for launching in external browser
1079            }
1080            catch (Exception ex) {
1081                log.debug("Open New Dataset Help failure: ", ex);
1082            }
1083        }
1084    }
1085}