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