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 http://hdfgroup.org/products/hdf-java/doc/Copyright.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;
016
017import java.awt.BorderLayout;
018import java.awt.Color;
019import java.awt.Dimension;
020import java.awt.GridLayout;
021import java.awt.Point;
022import java.awt.Toolkit;
023import java.awt.event.ActionEvent;
024import java.awt.event.ActionListener;
025import java.awt.event.ItemEvent;
026import java.awt.event.ItemListener;
027import java.awt.event.KeyEvent;
028import java.net.URL;
029import java.net.URLClassLoader;
030import java.util.Iterator;
031import java.util.List;
032import java.util.StringTokenizer;
033import java.util.Vector;
034
035import javax.swing.BorderFactory;
036import javax.swing.ButtonGroup;
037import javax.swing.JButton;
038import javax.swing.JCheckBox;
039import javax.swing.JComboBox;
040import javax.swing.JDialog;
041import javax.swing.JEditorPane;
042import javax.swing.JFrame;
043import javax.swing.JLabel;
044import javax.swing.JOptionPane;
045import javax.swing.JPanel;
046import javax.swing.JRadioButton;
047import javax.swing.JScrollPane;
048import javax.swing.JTextField;
049import javax.swing.border.TitledBorder;
050import javax.swing.event.HyperlinkEvent;
051import javax.swing.event.HyperlinkListener;
052import javax.swing.text.html.HTMLDocument;
053import javax.swing.text.html.HTMLFrameHyperlinkEvent;
054
055import hdf.object.DataFormat;
056import hdf.object.Dataset;
057import hdf.object.Datatype;
058import hdf.object.FileFormat;
059import hdf.object.Group;
060import hdf.object.HObject;
061import hdf.object.ScalarDS;
062
063/**
064 * NewDatasetDialog shows a message dialog requesting user input for creating a
065 * new HDF4/5 dataset.
066 *
067 * @author Peter X. Cao
068 * @version 2.4 9/6/2007
069 */
070public class NewDatasetDialog extends JDialog implements ActionListener, ItemListener, HyperlinkListener {
071    private static final long serialVersionUID = 5381164938654184532L;
072
073    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(NewDatasetDialog.class);
074
075    private JTextField        nameField, currentSizeField, maxSizeField, chunkSizeField, stringLengthField,
076    fillValueField;
077
078    @SuppressWarnings("rawtypes")
079    private JComboBox         parentChoice, classChoice, sizeChoice, endianChoice, rankChoice, compressionLevel;
080
081    private JCheckBox         checkUnsigned, checkCompression, checkFillValue;
082
083    private JRadioButton      checkContinguous, checkChunked;
084
085    private JDialog           helpDialog;
086
087    private boolean           isH5;
088
089    /** a list of current groups */
090    private List<Object>      groupList;
091
092    private HObject           newObject;
093
094    private FileFormat        fileFormat;
095
096    private final Toolkit     toolkit;
097
098    private final DataView    dataView;
099
100    /**
101     * Constructs NewDatasetDialog with specified list of possible parent
102     * groups.
103     *
104     * @param owner
105     *            the owner of the input
106     * @param pGroup
107     *            the parent group which the new group is added to.
108     * @param objs
109     *            the list of all objects.
110     */
111    @SuppressWarnings({ "rawtypes", "unchecked" })
112    public NewDatasetDialog(JFrame owner, Group pGroup, List<?> objs) {
113        super(owner, "New Dataset...", true);
114
115        helpDialog = null;
116        newObject = null;
117        dataView = null;
118
119        fileFormat = pGroup.getFileFormat();
120        toolkit = Toolkit.getDefaultToolkit();
121        isH5 = pGroup.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5));
122
123        parentChoice = new JComboBox();
124        groupList = new Vector<Object>();
125        Object obj = null;
126        Iterator<?> iterator = objs.iterator();
127        while (iterator.hasNext()) {
128            obj = iterator.next();
129            if (obj instanceof Group) {
130                Group g = (Group) obj;
131                groupList.add(obj);
132                if (g.isRoot()) {
133                    parentChoice.addItem(HObject.separator);
134                }
135                else {
136                    parentChoice.addItem(g.getPath() + g.getName() + HObject.separator);
137                }
138            }
139        }
140
141        if (pGroup.isRoot()) {
142            parentChoice.setSelectedItem(HObject.separator);
143        }
144        else {
145            parentChoice.setSelectedItem(pGroup.getPath() + pGroup.getName() + HObject.separator);
146        }
147
148        JPanel contentPane = (JPanel) getContentPane();
149        contentPane.setLayout(new BorderLayout(5, 5));
150        contentPane.setBorder(BorderFactory.createEmptyBorder(15, 5, 5, 5));
151        int w = 600 + (ViewProperties.getFontSize() - 12) * 15;
152        int h = 350 + (ViewProperties.getFontSize() - 12) * 10;
153        contentPane.setPreferredSize(new Dimension(w, h));
154
155        JButton okButton = new JButton("   Ok   ");
156        okButton.setName("OK");
157        okButton.setActionCommand("Ok");
158        okButton.setMnemonic(KeyEvent.VK_O);
159        okButton.addActionListener(this);
160
161        JButton cancelButton = new JButton("Cancel");
162        cancelButton.setName("Cancel");
163        cancelButton.setMnemonic(KeyEvent.VK_C);
164        cancelButton.setActionCommand("Cancel");
165        cancelButton.addActionListener(this);
166
167        JButton helplButton = new JButton("Help");
168        helplButton.setName("Help");
169        helplButton.setMnemonic(KeyEvent.VK_H);
170        helplButton.setActionCommand("Show help");
171        helplButton.addActionListener(this);
172
173        // set OK and CANCEL buttons
174        JPanel buttonPanel = new JPanel();
175        buttonPanel.add(okButton);
176        buttonPanel.add(cancelButton);
177        buttonPanel.add(helplButton);
178        contentPane.add(buttonPanel, BorderLayout.SOUTH);
179
180        // set NAME and PARENT GROUP panel
181        JPanel namePanel = new JPanel();
182        namePanel.setLayout(new BorderLayout(5, 5));
183        JPanel tmpP = new JPanel();
184        tmpP.setLayout(new GridLayout(2, 1));
185        tmpP.add(new JLabel("Dataset name: "));
186        tmpP.add(new JLabel("Parent group: "));
187        namePanel.add(tmpP, BorderLayout.WEST);
188        tmpP = new JPanel();
189        tmpP.setLayout(new GridLayout(2, 1));
190        tmpP.add(nameField = new JTextField());
191        nameField.setName("datasetname");
192        tmpP.add(parentChoice);
193        namePanel.add(tmpP, BorderLayout.CENTER);
194        contentPane.add(namePanel, BorderLayout.NORTH);
195
196        // set DATATYPE
197        JPanel typePanel = new JPanel();
198        typePanel.setLayout(new GridLayout(2, 4, 15, 3));
199        TitledBorder border = new TitledBorder("Datatype");
200        border.setTitleColor(Color.gray);
201        typePanel.setBorder(border);
202
203        stringLengthField = new JTextField("String length");
204        stringLengthField.setName("datasetstringlen");
205        stringLengthField.setEnabled(false);
206
207        endianChoice = new JComboBox();
208        endianChoice.setName("datasetendian");
209        classChoice = new JComboBox();
210        classChoice.setName("datasetclass");
211        sizeChoice = new JComboBox();
212        sizeChoice.setName("datasetsize");
213        endianChoice.setEnabled(isH5);
214
215        classChoice.addItem("INTEGER");
216        classChoice.addItem("FLOAT");
217        classChoice.addItem("CHAR");
218
219        if (isH5) {
220            classChoice.addItem("STRING");
221            classChoice.addItem("REFERENCE");
222            classChoice.addItem("ENUM");
223            classChoice.addItem("VLEN_INTEGER");
224            classChoice.addItem("VLEN_FLOAT");
225            classChoice.addItem("VLEN_STRING");
226            sizeChoice.addItem("NATIVE");
227            endianChoice.addItem("NATIVE");
228            endianChoice.addItem("LITTLE ENDIAN");
229            endianChoice.addItem("BIG ENDIAN");
230        }
231        else {
232            sizeChoice.addItem("DEFAULT");
233            endianChoice.addItem("DEFAULT");
234        }
235        sizeChoice.addItem("8");
236        sizeChoice.addItem("16");
237        sizeChoice.addItem("32");
238        sizeChoice.addItem("64");
239
240        typePanel.add(new JLabel("Datatype class"));
241        typePanel.add(new JLabel("Size (bits)"));
242        typePanel.add(new JLabel("Byte ordering"));
243        checkUnsigned = new JCheckBox("Unsigned");
244        checkUnsigned.setName("datasetchkunsigned");
245        typePanel.add(checkUnsigned);
246
247        typePanel.add(classChoice);
248        typePanel.add(sizeChoice);
249        typePanel.add(endianChoice);
250        typePanel.add(stringLengthField);
251
252        // set DATATSPACE
253        JPanel spacePanel = new JPanel();
254        spacePanel.setLayout(new GridLayout(2, 3, 15, 3));
255        border = new TitledBorder("Dataspace");
256        border.setTitleColor(Color.gray);
257        spacePanel.setBorder(border);
258
259        rankChoice = new JComboBox();
260        rankChoice.setName("datasetrank");
261        for (int i = 1; i < 33; i++) {
262            rankChoice.addItem(String.valueOf(i));
263        }
264        rankChoice.setSelectedIndex(1);
265
266        currentSizeField = new JTextField("1 x 1");
267        currentSizeField.setName("currentsize");
268        maxSizeField = new JTextField("");
269        spacePanel.add(new JLabel("No. of dimensions"));
270        spacePanel.add(new JLabel("Current size"));
271        spacePanel.add(new JLabel(""));
272        spacePanel.add(rankChoice);
273        spacePanel.add(currentSizeField);
274        JButton jb = new JButton("Set Max Size");
275        jb.setActionCommand("Set max size");
276        jb.addActionListener(this);
277        spacePanel.add(jb);
278        // spacePanel.add(maxSizeField);
279
280        // set storage layout and data compression
281        JPanel layoutPanel = new JPanel();
282        layoutPanel.setLayout(new BorderLayout());
283        border = new TitledBorder("Storage Properties");
284        border.setTitleColor(Color.gray);
285        layoutPanel.setBorder(border);
286
287        checkContinguous = new JRadioButton("Contiguous");
288        checkContinguous.setName("datasetcontinguous");
289        checkContinguous.setSelected(true);
290        checkChunked = new JRadioButton("Chunked (size) ");
291        checkChunked.setName("datasetchunk");
292        ButtonGroup bgroup = new ButtonGroup();
293        bgroup.add(checkChunked);
294        bgroup.add(checkContinguous);
295        chunkSizeField = new JTextField("1 x 1");
296        chunkSizeField.setName("datasetchunksize");
297        chunkSizeField.setEnabled(false);
298        checkCompression = new JCheckBox("gzip (level) ");
299        checkCompression.setName("datasetgzip");
300
301        compressionLevel = new JComboBox();
302        compressionLevel.setName("datasetlevel");
303        for (int i = 0; i < 10; i++) {
304            compressionLevel.addItem(String.valueOf(i));
305        }
306        compressionLevel.setSelectedIndex(6);
307        compressionLevel.setEnabled(false);
308
309        tmpP = new JPanel();
310        tmpP.setLayout(new GridLayout(2, 1));
311        tmpP.add(new JLabel("Storage layout:  "));
312        tmpP.add(new JLabel("Compression:  "));
313        layoutPanel.add(tmpP, BorderLayout.WEST);
314
315        tmpP = new JPanel();
316        tmpP.setLayout(new GridLayout(2, 1));
317
318        // storage layout
319        JPanel tmpP0 = new JPanel();
320        tmpP0.setLayout(new GridLayout(1, 3, 0, 5));
321        tmpP0.add(checkContinguous);
322        JPanel tmpP00 = new JPanel();
323        tmpP00.setLayout(new BorderLayout());
324        tmpP00.add(checkChunked, BorderLayout.WEST);
325        tmpP00.add(chunkSizeField, BorderLayout.CENTER);
326        tmpP0.add(tmpP00);
327        tmpP0.add(new JLabel(""));
328        tmpP.add(tmpP0);
329
330        tmpP0 = new JPanel();
331        tmpP0.setLayout(new GridLayout(1, 2, 30, 5));
332
333        // compression
334        tmpP00 = new JPanel();
335        tmpP00.setLayout(new BorderLayout());
336        tmpP00.add(checkCompression, BorderLayout.WEST);
337        tmpP00.add(compressionLevel, BorderLayout.CENTER);
338        tmpP0.add(tmpP00);
339
340        // fill values
341        checkFillValue = new JCheckBox("Fill Value ");
342        checkFillValue.setName("datasetchkfill");
343        fillValueField = new JTextField("0");
344        fillValueField.setName("datasetfillval");
345        fillValueField.setEnabled(false);
346        checkFillValue.setSelected(false);
347        tmpP00 = new JPanel();
348        tmpP00.setLayout(new BorderLayout());
349        tmpP00.add(checkFillValue, BorderLayout.WEST);
350        tmpP00.add(fillValueField, BorderLayout.CENTER);
351
352        if (isH5)
353            tmpP0.add(tmpP00);
354        else
355            tmpP0.add(new JLabel(""));
356
357        tmpP.add(tmpP0);
358
359        layoutPanel.add(tmpP, BorderLayout.CENTER);
360
361        JPanel infoPanel = new JPanel();
362        infoPanel.setLayout(new GridLayout(3, 1, 5, 10));
363        infoPanel.add(typePanel);
364        infoPanel.add(spacePanel);
365        infoPanel.add(layoutPanel);
366        contentPane.add(infoPanel, BorderLayout.CENTER);
367
368        classChoice.addItemListener(this);
369        sizeChoice.addItemListener(this);
370        rankChoice.addItemListener(this);
371        checkCompression.addItemListener(this);
372        checkFillValue.addItemListener(this);
373        checkContinguous.addItemListener(this);
374        checkChunked.addItemListener(this);
375
376        // locate the H5Property dialog
377        Point l = owner.getLocation();
378        l.x += 250;
379        l.y += 80;
380        setLocation(l);
381        validate();
382        pack();
383    }
384
385    /**
386     * Constructs NewDatasetDialog with specified list of possible parent
387     * groups.
388     *
389     * @param owner
390     *            the owner of the input
391     * @param pGroup
392     *            the parent group which the new group is added to.
393     * @param objs
394     *            the list of all objects.
395     */
396    @SuppressWarnings({ "rawtypes", "unchecked" })
397    public NewDatasetDialog(JFrame owner, Group pGroup, List<?> objs, DataView observer) {
398        super(owner, "New Dataset...", true);
399
400        helpDialog = null;
401        newObject = null;
402        dataView = observer;
403
404        fileFormat = pGroup.getFileFormat();
405        toolkit = Toolkit.getDefaultToolkit();
406        isH5 = pGroup.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5));
407
408        parentChoice = new JComboBox();
409        groupList = new Vector<Object>();
410        Object obj = null;
411        Iterator<?> iterator = objs.iterator();
412        while (iterator.hasNext()) {
413            obj = iterator.next();
414            if (obj instanceof Group) {
415                Group g = (Group) obj;
416                groupList.add(obj);
417                if (g.isRoot()) {
418                    parentChoice.addItem(HObject.separator);
419                }
420                else {
421                    parentChoice.addItem(g.getPath() + g.getName() + HObject.separator);
422                }
423            }
424        }
425
426        if (pGroup.isRoot()) {
427            parentChoice.setSelectedItem(HObject.separator);
428        }
429        else {
430            parentChoice.setSelectedItem(pGroup.getPath() + pGroup.getName() + HObject.separator);
431        }
432
433        JPanel contentPane = (JPanel) getContentPane();
434        contentPane.setLayout(new BorderLayout(5, 5));
435        contentPane.setBorder(BorderFactory.createEmptyBorder(15, 5, 5, 5));
436        int w = 400 + (ViewProperties.getFontSize() - 12) * 15;
437        int h = 120 + (ViewProperties.getFontSize() - 12) * 10;
438        contentPane.setPreferredSize(new Dimension(w, h));
439
440        JButton okButton = new JButton("   Ok   ");
441        okButton.setActionCommand("Ok");
442        okButton.setMnemonic(KeyEvent.VK_O);
443        okButton.addActionListener(this);
444
445        JButton cancelButton = new JButton("Cancel");
446        cancelButton.setMnemonic(KeyEvent.VK_C);
447        cancelButton.setActionCommand("Cancel");
448        cancelButton.addActionListener(this);
449
450        // set OK and CANCEL buttons
451        JPanel buttonPanel = new JPanel();
452        buttonPanel.add(okButton);
453        buttonPanel.add(cancelButton);
454        contentPane.add(buttonPanel, BorderLayout.SOUTH);
455
456        // set NAME and PARENT GROUP panel
457        JPanel namePanel = new JPanel();
458        namePanel.setLayout(new BorderLayout(5, 5));
459        JPanel tmpP = new JPanel();
460        tmpP.setLayout(new GridLayout(2, 1));
461        tmpP.add(new JLabel("Dataset name: "));
462        tmpP.add(new JLabel("Parent group: "));
463        namePanel.add(tmpP, BorderLayout.WEST);
464        tmpP = new JPanel();
465        tmpP.setLayout(new GridLayout(2, 1));
466        tmpP.add(nameField = new JTextField(((HObject) observer.getDataObject()).getName() + "~copy", 40));
467        tmpP.add(parentChoice);
468        namePanel.add(tmpP, BorderLayout.CENTER);
469        contentPane.add(namePanel, BorderLayout.CENTER);
470
471        // locate the H5Property dialog
472        Point l = owner.getLocation();
473        l.x += 250;
474        l.y += 80;
475        setLocation(l);
476        pack();
477    }
478
479    public void actionPerformed(ActionEvent e) {
480        String cmd = e.getActionCommand();
481
482        if (cmd.equals("Ok")) {
483            if (dataView instanceof TableView) {
484                newObject = createFromTable();
485            }
486            else if (dataView instanceof ImageView) {
487                newObject = createFromImage();
488            }
489            else if (dataView == null) {
490                newObject = createFromScratch();
491            }
492
493            if (newObject != null) {
494                dispose();
495            }
496        }
497        if (cmd.equals("Cancel")) {
498            newObject = null;
499            dispose();
500            ((Vector<Object>) groupList).setSize(0);
501        }
502        else if (cmd.equals("Show help")) {
503            if (helpDialog == null) {
504                createHelpDialog();
505            }
506            helpDialog.setVisible(true);
507        }
508        else if (cmd.equals("Hide help")) {
509            if (helpDialog != null) {
510                helpDialog.setVisible(false);
511            }
512        }
513        else if (cmd.equals("Set max size")) {
514            String strMax = maxSizeField.getText();
515            if (strMax == null || strMax.length() < 1) strMax = currentSizeField.getText();
516
517            String msg = JOptionPane.showInputDialog(this, "Enter max dimension sizes. \n"
518                    + "Use \"unlimited\" for unlimited dimension size.\n\n" + "For example,\n" + "    200 x 100\n"
519                    + "    100 x unlimited\n\n", strMax);
520
521            if (msg == null || msg.length() < 1)
522                maxSizeField.setText(currentSizeField.getText());
523            else
524                maxSizeField.setText(msg);
525
526            checkMaxSize();
527        }
528    }
529
530    @SuppressWarnings("unchecked")
531    public void itemStateChanged(ItemEvent e) {
532        Object source = e.getSource();
533
534        if (source.equals(classChoice)) {
535            int idx = classChoice.getSelectedIndex();
536            sizeChoice.setSelectedIndex(0);
537            endianChoice.setSelectedIndex(0);
538            stringLengthField.setEnabled(false);
539
540            if ((idx == 0) || (idx == 6)) { // INTEGER
541                sizeChoice.setEnabled(true);
542                endianChoice.setEnabled(isH5);
543                checkUnsigned.setEnabled(true);
544
545                if (sizeChoice.getItemCount() == 3) {
546                    sizeChoice.removeItem("32");
547                    sizeChoice.removeItem("64");
548                    sizeChoice.addItem("8");
549                    sizeChoice.addItem("16");
550                    sizeChoice.addItem("32");
551                    sizeChoice.addItem("64");
552                }
553            }
554            else if ((idx == 1) || (idx == 7)) { // FLOAT
555                sizeChoice.setEnabled(true);
556                endianChoice.setEnabled(isH5);
557                checkUnsigned.setEnabled(false);
558
559                if (sizeChoice.getItemCount() == 5) {
560                    sizeChoice.removeItem("16");
561                    sizeChoice.removeItem("8");
562                }
563            }
564            else if (idx == 2) { // CHAR
565                sizeChoice.setEnabled(false);
566                endianChoice.setEnabled(isH5);
567                checkUnsigned.setEnabled(true);
568            }
569            else if (idx == 3) { // STRING
570                sizeChoice.setEnabled(false);
571                endianChoice.setEnabled(false);
572                checkUnsigned.setEnabled(false);
573                stringLengthField.setEnabled(true);
574                stringLengthField.setText("String length");
575            }
576            else if (idx == 4) { // REFERENCE
577                sizeChoice.setEnabled(false);
578                endianChoice.setEnabled(false);
579                checkUnsigned.setEnabled(false);
580                stringLengthField.setEnabled(false);
581            }
582            else if (idx == 5) { // ENUM
583                sizeChoice.setEnabled(true);
584                checkUnsigned.setEnabled(true);
585                stringLengthField.setEnabled(true);
586                stringLengthField.setText("R=0,G=1,B=2,...");
587            }
588            else if (idx == 8) {
589                sizeChoice.setEnabled(false);
590                endianChoice.setEnabled(false);
591                checkUnsigned.setEnabled(false);
592                stringLengthField.setEnabled(false);
593            }
594        }
595        else if (source.equals(sizeChoice)) {
596            if (classChoice.getSelectedIndex() == 0) {
597                checkUnsigned.setEnabled(true);
598            }
599        }
600        else if (source.equals(rankChoice)) {
601            int rank = rankChoice.getSelectedIndex() + 1;
602            String currentSizeStr = "1";
603            String maxSizeStr = "0";
604
605            for (int i = 1; i < rank; i++) {
606                currentSizeStr += " x 1";
607                maxSizeStr += " x 0";
608            }
609
610            currentSizeField.setText(currentSizeStr);
611            maxSizeField.setText(maxSizeStr);
612
613            String currentStr = currentSizeField.getText();
614            int idx = currentStr.lastIndexOf("x");
615            String chunkStr = "1";
616
617            if (rank <= 1) {
618                chunkStr = currentStr;
619            }
620            else {
621                for (int i = 1; i < rank - 1; i++) {
622                    chunkStr += " x 1";
623                }
624                if (idx > 0) {
625                    chunkStr += " x " + currentStr.substring(idx + 1);
626                }
627            }
628
629            chunkSizeField.setText(chunkStr);
630        }
631        else if (source.equals(checkContinguous)) {
632            chunkSizeField.setEnabled(false);
633        }
634        else if (source.equals(checkChunked)) {
635            chunkSizeField.setEnabled(true);
636            String chunkStr = "";
637            StringTokenizer st = new StringTokenizer(currentSizeField.getText(), "x");
638            int rank = rankChoice.getSelectedIndex() + 1;
639            while (st.hasMoreTokens()) {
640                long l = Math.max(1, Long.valueOf(st.nextToken().trim()) / (2 * rank));
641                chunkStr += String.valueOf(l) + "x";
642            }
643            chunkStr = chunkStr.substring(0, chunkStr.lastIndexOf('x'));
644            chunkSizeField.setText(chunkStr);
645        }
646        else if (source.equals(checkCompression)) {
647            boolean isCompressed = checkCompression.isSelected();
648
649            if (isCompressed && isH5) {
650                if (!checkChunked.isSelected()) {
651                    String currentStr = currentSizeField.getText();
652                    int idx = currentStr.lastIndexOf("x");
653                    String chunkStr = "1";
654
655                    int rank = rankChoice.getSelectedIndex() + 1;
656                    if (rank <= 1) {
657                        chunkStr = currentStr;
658                    }
659                    else {
660                        for (int i = 1; i < rank - 1; i++) {
661                            chunkStr += " x 1";
662                        }
663                        if (idx > 0) {
664                            chunkStr += " x " + currentStr.substring(idx + 1);
665                        }
666                    }
667
668                    chunkSizeField.setText(chunkStr);
669                }
670                compressionLevel.setEnabled(true);
671                checkContinguous.setEnabled(false);
672                checkChunked.setSelected(true);
673                chunkSizeField.setEnabled(true);
674            }
675            else {
676                compressionLevel.setEnabled(isCompressed);
677                checkContinguous.setEnabled(true);
678            }
679        }
680        else if (source.equals(checkFillValue)) {
681            fillValueField.setEnabled(checkFillValue.isSelected());
682        }
683    }
684
685    /** check is the max size is valid */
686    private void checkMaxSize() {
687        boolean isChunkNeeded = false;
688        String dimStr = currentSizeField.getText();
689        String maxStr = maxSizeField.getText();
690        StringTokenizer stMax = new StringTokenizer(maxStr, "x");
691        StringTokenizer stDim = new StringTokenizer(dimStr, "x");
692
693        if (stMax.countTokens() != stDim.countTokens()) {
694            toolkit.beep();
695            JOptionPane.showMessageDialog(this, "Wrong number of values in the max dimension size " + maxStr,
696                    getTitle(), JOptionPane.ERROR_MESSAGE);
697            maxSizeField.setText(null);
698            return;
699        }
700
701        int rank = stDim.countTokens();
702        long max = 0, dim = 0;
703        long[] maxdims = new long[rank];
704        for (int i = 0; i < rank; i++) {
705            String token = stMax.nextToken().trim();
706
707            token = token.toLowerCase();
708            if (token.startsWith("u")) {
709                max = -1;
710                isChunkNeeded = true;
711            }
712            else {
713                try {
714                    max = Long.parseLong(token);
715                }
716                catch (NumberFormatException ex) {
717                    toolkit.beep();
718                    JOptionPane.showMessageDialog(this, "Invalid max dimension size: " + maxStr, getTitle(),
719                            JOptionPane.ERROR_MESSAGE);
720                    maxSizeField.setText(null);
721                    return;
722                }
723            }
724
725            token = stDim.nextToken().trim();
726            try {
727                dim = Long.parseLong(token);
728            }
729            catch (NumberFormatException ex) {
730                toolkit.beep();
731                JOptionPane.showMessageDialog(this, "Invalid dimension size: " + dimStr, getTitle(),
732                        JOptionPane.ERROR_MESSAGE);
733                return;
734            }
735
736            if (max != -1 && max < dim) {
737                toolkit.beep();
738                JOptionPane.showMessageDialog(this, "Invalid max dimension size: " + maxStr, getTitle(),
739                        JOptionPane.ERROR_MESSAGE);
740                maxSizeField.setText(null);
741                return;
742            }
743            else if (max > dim) {
744                isChunkNeeded = true;
745            }
746
747            maxdims[i] = max;
748        } // for (int i = 0; i < rank; i++)
749
750        if (isH5) {
751            if (isChunkNeeded && !checkChunked.isSelected()) {
752                toolkit.beep();
753                JOptionPane.showMessageDialog(this, "Chunking is required for the max dimensions of " + maxStr,
754                        getTitle(), JOptionPane.ERROR_MESSAGE);
755                checkChunked.setSelected(true);
756            }
757        }
758        else {
759            for (int i = 1; i < rank; i++) {
760                if (maxdims[i] <= 0) {
761                    maxSizeField.setText(currentSizeField.getText());
762                    toolkit.beep();
763                    JOptionPane.showMessageDialog(this, "Only dim[0] can be unlimited." + maxStr, getTitle(),
764                            JOptionPane.ERROR_MESSAGE);
765                    return;
766                }
767            }
768        }
769    }
770
771    /** Creates a dialog to show the help information. */
772    private void createHelpDialog() {
773        helpDialog = new JDialog(this, "Create New Dataset");
774
775        JPanel contentPane = (JPanel) helpDialog.getContentPane();
776        contentPane.setLayout(new BorderLayout(5, 5));
777        contentPane.setBorder(BorderFactory.createEmptyBorder(15, 5, 5, 5));
778        int w = 500 + (ViewProperties.getFontSize() - 12) * 15;
779        int h = 400 + (ViewProperties.getFontSize() - 12) * 10;
780        contentPane.setPreferredSize(new Dimension(w, h));
781
782        JButton b = new JButton("  Ok  ");
783        b.addActionListener(this);
784        b.setActionCommand("Hide help");
785        JPanel tmpP = new JPanel();
786        tmpP.add(b);
787        contentPane.add(tmpP, BorderLayout.SOUTH);
788
789        JEditorPane infoPane = new JEditorPane();
790        infoPane.setEditable(false);
791        JScrollPane editorScrollPane = new JScrollPane(infoPane);
792        contentPane.add(editorScrollPane, BorderLayout.CENTER);
793
794        try {
795            URL url = null, url2 = null, url3 = null;
796            String rootPath = ViewProperties.getViewRoot();
797
798            try {
799                url = new URL("file:" + rootPath + "/lib/jhdfview.jar");
800            }
801            catch (java.net.MalformedURLException mfu) {
802                log.debug("help information:", mfu);
803            }
804
805            try {
806                url2 = new URL("file:" + rootPath + "/");
807            }
808            catch (java.net.MalformedURLException mfu) {
809                log.debug("help information:", mfu);
810            }
811
812            try {
813                url3 = new URL("file:" + rootPath + "/src/");
814            }
815            catch (java.net.MalformedURLException mfu) {
816                log.debug("help information:", mfu);
817            }
818
819            URL uu[] = { url, url2, url3 };
820            URLClassLoader cl = new URLClassLoader(uu);
821            URL u = cl.findResource("hdf/view/NewDatasetHelp.html");
822
823            infoPane.setPage(u);
824            infoPane.addHyperlinkListener(this);
825        }
826        catch (Exception e) {
827            infoPane.setContentType("text/html");
828            StringBuffer buff = new StringBuffer();
829            buff.append("<html>");
830            buff.append("<body>");
831            buff.append("ERROR: cannot load help information.");
832            buff.append("</body>");
833            buff.append("</html>");
834            infoPane.setText(buff.toString());
835        }
836
837        Point l = helpDialog.getOwner().getLocation();
838        l.x += 50;
839        l.y += 80;
840        helpDialog.setLocation(l);
841        helpDialog.validate();
842        helpDialog.pack();
843    }
844
845    public void hyperlinkUpdate(HyperlinkEvent e) {
846        if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
847            JEditorPane pane = (JEditorPane) e.getSource();
848
849            if (e instanceof HTMLFrameHyperlinkEvent) {
850                HTMLFrameHyperlinkEvent evt = (HTMLFrameHyperlinkEvent) e;
851                HTMLDocument doc = (HTMLDocument) pane.getDocument();
852                doc.processHTMLFrameHyperlinkEvent(evt);
853            }
854            else {
855                try {
856                    pane.setPage(e.getURL());
857                }
858                catch (Throwable t) {
859                    log.debug("JEditorPane hyperlink:", t);
860                }
861            }
862        }
863    }
864
865    private HObject createFromScratch() {
866        String name = null;
867        Group pgroup = null;
868        boolean isVLen = false;
869        int rank = -1, gzip = -1, tclass = -1, tsize = -1, torder = -1, tsign = -1;
870        long dims[], maxdims[] = null, chunks[] = null;
871
872        name = nameField.getText().trim();
873        if ((name == null) || (name.length() < 1)) {
874            toolkit.beep();
875            JOptionPane
876            .showMessageDialog(this, "Dataset name is not specified.", getTitle(), JOptionPane.ERROR_MESSAGE);
877            return null;
878        }
879
880        if (name.indexOf(HObject.separator) >= 0) {
881            toolkit.beep();
882            JOptionPane.showMessageDialog(this, "Dataset name cannot contain path.", getTitle(),
883                    JOptionPane.ERROR_MESSAGE);
884            return null;
885        }
886
887        pgroup = (Group) groupList.get(parentChoice.getSelectedIndex());
888
889        if (pgroup == null) {
890            toolkit.beep();
891            JOptionPane.showMessageDialog(this, "Parent group is null.", getTitle(), JOptionPane.ERROR_MESSAGE);
892            return null;
893        }
894
895        // set datatype class
896        int idx = classChoice.getSelectedIndex();
897        if (idx == 0) {
898            tclass = Datatype.CLASS_INTEGER;
899            if (checkUnsigned.isSelected()) {
900                tsign = Datatype.SIGN_NONE;
901            }
902        }
903        else if (idx == 1) {
904            tclass = Datatype.CLASS_FLOAT;
905        }
906        else if (idx == 2) {
907            tclass = Datatype.CLASS_CHAR;
908            if (checkUnsigned.isSelected()) {
909                tsign = Datatype.SIGN_NONE;
910            }
911        }
912        else if (idx == 3) {
913            tclass = Datatype.CLASS_STRING;
914        }
915        else if (idx == 4) {
916            tclass = Datatype.CLASS_REFERENCE;
917        }
918        else if (idx == 5) {
919            tclass = Datatype.CLASS_ENUM;
920        }
921        else if (idx == 6) {
922            isVLen = true;
923            tclass = Datatype.CLASS_INTEGER;
924            if (checkUnsigned.isSelected()) {
925                tsign = Datatype.SIGN_NONE;
926            }
927        }
928        else if (idx == 7) {
929            isVLen = true;
930            tclass = Datatype.CLASS_FLOAT;
931        }
932        else if (idx == 8) {
933            isVLen = true;
934            tclass = Datatype.CLASS_STRING;
935        }
936
937        // set datatype size/order
938        idx = sizeChoice.getSelectedIndex();
939        if (tclass == Datatype.CLASS_STRING) {
940            if (isVLen) {
941                tsize = -1;
942            }
943            else {
944                int stringLength = 0;
945                try {
946                    stringLength = Integer.parseInt(stringLengthField.getText());
947                }
948                catch (NumberFormatException ex) {
949                    stringLength = -1;
950                }
951
952                if (stringLength <= 0) {
953                    toolkit.beep();
954                    JOptionPane.showMessageDialog(this, "Invalid string length: " + stringLengthField.getText(),
955                            getTitle(), JOptionPane.ERROR_MESSAGE);
956                    return null;
957                }
958                tsize = stringLength;
959            }
960        }
961        else if (tclass == Datatype.CLASS_ENUM) {
962            String enumStr = stringLengthField.getText();
963            if ((enumStr == null) || (enumStr.length() < 1) || enumStr.endsWith("...")) {
964                toolkit.beep();
965                JOptionPane.showMessageDialog(this, "Invalid member values: " + stringLengthField.getText(),
966                        getTitle(), JOptionPane.ERROR_MESSAGE);
967                return null;
968            }
969        }
970        else if (tclass == Datatype.CLASS_REFERENCE) {
971            tsize = 1;
972        }
973        else if (idx == 0) {
974            tsize = Datatype.NATIVE;
975        }
976        else if (tclass == Datatype.CLASS_FLOAT) {
977            tsize = idx * 4;
978        }
979        else {
980            tsize = 1 << (idx - 1);
981        }
982
983        if ((tsize == 8) && !isH5 && (tclass == Datatype.CLASS_INTEGER)) {
984            toolkit.beep();
985            JOptionPane.showMessageDialog(this, "HDF4 does not support 64-bit integer.", getTitle(),
986                    JOptionPane.ERROR_MESSAGE);
987            return null;
988        }
989
990        // set order
991        idx = endianChoice.getSelectedIndex();
992        if (idx == 0) {
993            torder = Datatype.NATIVE;
994        }
995        else if (idx == 1) {
996            torder = Datatype.ORDER_LE;
997        }
998        else {
999            torder = Datatype.ORDER_BE;
1000        }
1001
1002        rank = rankChoice.getSelectedIndex() + 1;
1003        StringTokenizer st = new StringTokenizer(currentSizeField.getText(), "x");
1004        if (st.countTokens() < rank) {
1005            toolkit.beep();
1006            JOptionPane.showMessageDialog(this, "Number of values in the current dimension size is less than " + rank,
1007                    getTitle(), JOptionPane.ERROR_MESSAGE);
1008            return null;
1009        }
1010
1011        long l = 0;
1012        dims = new long[rank];
1013        String token = null;
1014        for (int i = 0; i < rank; i++) {
1015            token = st.nextToken().trim();
1016            try {
1017                l = Long.parseLong(token);
1018            }
1019            catch (NumberFormatException ex) {
1020                toolkit.beep();
1021                JOptionPane.showMessageDialog(this, "Invalid dimension size: " + currentSizeField.getText(),
1022                        getTitle(), JOptionPane.ERROR_MESSAGE);
1023                return null;
1024            }
1025
1026            if (l <= 0) {
1027                toolkit.beep();
1028                JOptionPane.showMessageDialog(this, "Dimension size must be greater than zero.", getTitle(),
1029                        JOptionPane.ERROR_MESSAGE);
1030                return null;
1031            }
1032
1033            dims[i] = l;
1034        }
1035
1036        String maxFieldStr = maxSizeField.getText();
1037        if (maxFieldStr != null && maxFieldStr.length() > 1) {
1038            st = new StringTokenizer(maxFieldStr, "x");
1039            if (st.countTokens() < rank) {
1040                toolkit.beep();
1041                JOptionPane.showMessageDialog(this, "Number of values in the max dimension size is less than " + rank,
1042                        getTitle(), JOptionPane.ERROR_MESSAGE);
1043                return null;
1044            }
1045
1046            l = 0;
1047            maxdims = new long[rank];
1048            for (int i = 0; i < rank; i++) {
1049                token = st.nextToken().trim();
1050
1051                token = token.toLowerCase();
1052                if (token.startsWith("u"))
1053                    l = -1;
1054                else {
1055                    try {
1056                        l = Long.parseLong(token);
1057                    }
1058                    catch (NumberFormatException ex) {
1059                        toolkit.beep();
1060                        JOptionPane.showMessageDialog(this, "Invalid max dimension size: " + maxSizeField.getText(),
1061                                getTitle(), JOptionPane.ERROR_MESSAGE);
1062                        return null;
1063                    }
1064                }
1065
1066                if (l < -1) {
1067                    toolkit.beep();
1068                    JOptionPane.showMessageDialog(this, "Dimension size cannot be less than -1.", getTitle(),
1069                            JOptionPane.ERROR_MESSAGE);
1070                    return null;
1071                }
1072                else if (l == 0) {
1073                    l = dims[i];
1074                }
1075
1076                maxdims[i] = l;
1077            }
1078        }
1079
1080        chunks = null;
1081        if (checkChunked.isSelected()) {
1082            st = new StringTokenizer(chunkSizeField.getText(), "x");
1083            if (st.countTokens() < rank) {
1084                toolkit.beep();
1085                JOptionPane.showMessageDialog(this, "Number of values in the chunk size is less than " + rank,
1086                        getTitle(), JOptionPane.ERROR_MESSAGE);
1087                return null;
1088            }
1089
1090            l = 0;
1091            chunks = new long[rank];
1092            for (int i = 0; i < rank; i++) {
1093                token = st.nextToken().trim();
1094                try {
1095                    l = Long.parseLong(token);
1096                }
1097                catch (NumberFormatException ex) {
1098                    toolkit.beep();
1099                    JOptionPane.showMessageDialog(this, "Invalid chunk dimension size: " + chunkSizeField.getText(),
1100                            getTitle(), JOptionPane.ERROR_MESSAGE);
1101                    return null;
1102                }
1103
1104                if (l < 1) {
1105                    toolkit.beep();
1106                    JOptionPane.showMessageDialog(this, "Chunk size cannot be less than 1.", getTitle(),
1107                            JOptionPane.ERROR_MESSAGE);
1108                    return null;
1109                }
1110
1111                chunks[i] = l;
1112            } // for (int i=0; i<rank; i++)
1113
1114            long tchunksize = 1, tdimsize = 1;
1115            for (int i = 0; i < rank; i++) {
1116                tchunksize *= chunks[i];
1117                tdimsize *= dims[i];
1118            }
1119
1120            if (tchunksize >= tdimsize) {
1121                toolkit.beep();
1122                int status = JOptionPane.showConfirmDialog(this, "Chunk size is equal/greater than the current size. "
1123                        + "\nAre you sure you want to set chunk size to " + chunkSizeField.getText() + "?", getTitle(),
1124                        JOptionPane.YES_NO_OPTION);
1125                if (status == JOptionPane.NO_OPTION) {
1126                    return null;
1127                }
1128            }
1129
1130            if (tchunksize == 1) {
1131                toolkit.beep();
1132                int status = JOptionPane.showConfirmDialog(this,
1133                        "Chunk size is one, which may cause large memory overhead for large dataset."
1134                                + "\nAre you sure you want to set chunk size to " + chunkSizeField.getText() + "?",
1135                                getTitle(), JOptionPane.YES_NO_OPTION);
1136                if (status == JOptionPane.NO_OPTION) {
1137                    return null;
1138                }
1139            }
1140
1141        } // if (checkChunked.isSelected())
1142
1143        if (checkCompression.isSelected()) {
1144            gzip = compressionLevel.getSelectedIndex();
1145        }
1146        else {
1147            gzip = 0;
1148        }
1149
1150        HObject obj = null;
1151        try {
1152            Datatype basedatatype = null;
1153            if (isVLen) {
1154                basedatatype = fileFormat.createDatatype(tclass, tsize, torder, tsign);
1155                tclass = Datatype.CLASS_VLEN;
1156            }
1157            Datatype datatype = fileFormat.createDatatype(tclass, tsize, torder, tsign, basedatatype);
1158            if (tclass == Datatype.CLASS_ENUM) {
1159                datatype.setEnumMembers(stringLengthField.getText());
1160            }
1161            String fillValue = null;
1162            if (fillValueField.isEnabled()) fillValue = fillValueField.getText();
1163
1164            obj = fileFormat.createScalarDS(name, pgroup, datatype, dims, maxdims, chunks, gzip, fillValue, null);
1165        }
1166        catch (Exception ex) {
1167            toolkit.beep();
1168            JOptionPane.showMessageDialog(this, ex, getTitle(), JOptionPane.ERROR_MESSAGE);
1169            return null;
1170        }
1171
1172        return obj;
1173    }
1174
1175    private HObject createFromTable() {
1176        HObject obj = null;
1177
1178        String name = null;
1179        Group pgroup = null;
1180
1181        name = nameField.getText();
1182        if (name == null) {
1183            toolkit.beep();
1184            JOptionPane
1185            .showMessageDialog(this, "Dataset name is not specified.", getTitle(), JOptionPane.ERROR_MESSAGE);
1186            return null;
1187        }
1188
1189        if (name.indexOf(HObject.separator) >= 0) {
1190            toolkit.beep();
1191            JOptionPane.showMessageDialog(this, "Dataset name cannot contain path.", getTitle(),
1192                    JOptionPane.ERROR_MESSAGE);
1193            return null;
1194        }
1195
1196        pgroup = (Group) groupList.get(parentChoice.getSelectedIndex());
1197        if (pgroup == null) {
1198            toolkit.beep();
1199            JOptionPane.showMessageDialog(this, "Parent group is null.", getTitle(), JOptionPane.ERROR_MESSAGE);
1200            return null;
1201        }
1202
1203        TableView tableView = (TableView) dataView;
1204        Object theData = tableView.getSelectedData();
1205        if (theData == null) {
1206            return null;
1207        }
1208
1209        int w = tableView.getTable().getSelectedColumnCount();
1210        int h = tableView.getTable().getSelectedRowCount();
1211        Dataset dataset = (Dataset) tableView.getDataObject();
1212        if (dataset instanceof ScalarDS) {
1213            ScalarDS sd = (ScalarDS) dataset;
1214            if (sd.isUnsigned()) {
1215                theData = Dataset.convertToUnsignedC(theData, null);
1216            }
1217        }
1218
1219        try {
1220            long[] dims = { h, w };
1221            obj = dataset.copy(pgroup, name, dims, theData);
1222        }
1223        catch (Exception ex) {
1224            toolkit.beep();
1225            JOptionPane.showMessageDialog(this, ex.getMessage(), getTitle(), JOptionPane.ERROR_MESSAGE);
1226            return null;
1227        }
1228
1229        return obj;
1230    }
1231
1232    private HObject createFromImage() {
1233        HObject obj = null;
1234        String name = null;
1235        Group pgroup = null;
1236
1237        name = nameField.getText();
1238        if (name == null) {
1239            toolkit.beep();
1240            JOptionPane
1241            .showMessageDialog(this, "Dataset name is not specified.", getTitle(), JOptionPane.ERROR_MESSAGE);
1242            return null;
1243        }
1244
1245        if (name.indexOf(HObject.separator) >= 0) {
1246            toolkit.beep();
1247            JOptionPane.showMessageDialog(this, "Dataset name cannot contain path.", getTitle(),
1248                    JOptionPane.ERROR_MESSAGE);
1249            return null;
1250        }
1251
1252        pgroup = (Group) groupList.get(parentChoice.getSelectedIndex());
1253        if (pgroup == null) {
1254            toolkit.beep();
1255            JOptionPane.showMessageDialog(this, "Parent group is null.", getTitle(), JOptionPane.ERROR_MESSAGE);
1256            return null;
1257        }
1258
1259        ImageView imageView = (ImageView) dataView;
1260        ScalarDS dataset = (ScalarDS) imageView.getDataObject();
1261        Object theData = imageView.getSelectedData();
1262
1263        if (theData == null) {
1264            return null;
1265        }
1266
1267        // in version 2.4, unsigned image data is converted to signed data
1268        // to write data, the data needs to converted back to unsigned.
1269        if (dataset.isUnsigned()) {
1270            theData = Dataset.convertToUnsignedC(theData, null);
1271        }
1272
1273        int w = imageView.getSelectedArea().width;
1274        int h = imageView.getSelectedArea().height;
1275
1276        try {
1277            long[] dims = null;
1278            if (isH5) {
1279                if (imageView.isTrueColor()) {
1280                    dims = new long[3];
1281                    if (imageView.isPlaneInterlace()) {
1282                        dims[0] = 3;
1283                        dims[1] = h;
1284                        dims[2] = w;
1285                    }
1286                    else {
1287                        dims[0] = h;
1288                        dims[1] = w;
1289                        dims[2] = 3;
1290                    }
1291                }
1292                else {
1293                    dims = new long[2];
1294                    dims[0] = h;
1295                    dims[1] = w;
1296                }
1297            }
1298            else {
1299                dims = new long[2];
1300                dims[0] = w;
1301                dims[1] = h;
1302            }
1303
1304            obj = dataset.copy(pgroup, name, dims, theData);
1305        }
1306        catch (Exception ex) {
1307            toolkit.beep();
1308            JOptionPane.showMessageDialog(this, ex.getMessage(), getTitle(), JOptionPane.ERROR_MESSAGE);
1309            return null;
1310        }
1311
1312        return obj;
1313    }
1314
1315    /** Returns the new dataset created. */
1316    public DataFormat getObject() {
1317        return newObject;
1318    }
1319
1320    /** Returns the parent group of the new dataset. */
1321    public Group getParentGroup() {
1322        return (Group) groupList.get(parentChoice.getSelectedIndex());
1323    }
1324
1325}