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