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     * @param observer
396     *            the parent DataView
397     */
398    @SuppressWarnings({ "rawtypes", "unchecked" })
399    public NewDatasetDialog(JFrame owner, Group pGroup, List<?> objs, DataView observer) {
400        super(owner, "New Dataset...", true);
401
402        helpDialog = null;
403        newObject = null;
404        dataView = observer;
405
406        fileFormat = pGroup.getFileFormat();
407        toolkit = Toolkit.getDefaultToolkit();
408        isH5 = pGroup.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5));
409
410        parentChoice = new JComboBox();
411        groupList = new Vector<Object>();
412        Object obj = null;
413        Iterator<?> iterator = objs.iterator();
414        while (iterator.hasNext()) {
415            obj = iterator.next();
416            if (obj instanceof Group) {
417                Group g = (Group) obj;
418                groupList.add(obj);
419                if (g.isRoot()) {
420                    parentChoice.addItem(HObject.separator);
421                }
422                else {
423                    parentChoice.addItem(g.getPath() + g.getName() + HObject.separator);
424                }
425            }
426        }
427
428        if (pGroup.isRoot()) {
429            parentChoice.setSelectedItem(HObject.separator);
430        }
431        else {
432            parentChoice.setSelectedItem(pGroup.getPath() + pGroup.getName() + HObject.separator);
433        }
434
435        JPanel contentPane = (JPanel) getContentPane();
436        contentPane.setLayout(new BorderLayout(5, 5));
437        contentPane.setBorder(BorderFactory.createEmptyBorder(15, 5, 5, 5));
438        int w = 400 + (ViewProperties.getFontSize() - 12) * 15;
439        int h = 120 + (ViewProperties.getFontSize() - 12) * 10;
440        contentPane.setPreferredSize(new Dimension(w, h));
441
442        JButton okButton = new JButton("   Ok   ");
443        okButton.setActionCommand("Ok");
444        okButton.setMnemonic(KeyEvent.VK_O);
445        okButton.addActionListener(this);
446
447        JButton cancelButton = new JButton("Cancel");
448        cancelButton.setMnemonic(KeyEvent.VK_C);
449        cancelButton.setActionCommand("Cancel");
450        cancelButton.addActionListener(this);
451
452        // set OK and CANCEL buttons
453        JPanel buttonPanel = new JPanel();
454        buttonPanel.add(okButton);
455        buttonPanel.add(cancelButton);
456        contentPane.add(buttonPanel, BorderLayout.SOUTH);
457
458        // set NAME and PARENT GROUP panel
459        JPanel namePanel = new JPanel();
460        namePanel.setLayout(new BorderLayout(5, 5));
461        JPanel tmpP = new JPanel();
462        tmpP.setLayout(new GridLayout(2, 1));
463        tmpP.add(new JLabel("Dataset name: "));
464        tmpP.add(new JLabel("Parent group: "));
465        namePanel.add(tmpP, BorderLayout.WEST);
466        tmpP = new JPanel();
467        tmpP.setLayout(new GridLayout(2, 1));
468        tmpP.add(nameField = new JTextField(((HObject) observer.getDataObject()).getName() + "~copy", 40));
469        tmpP.add(parentChoice);
470        namePanel.add(tmpP, BorderLayout.CENTER);
471        contentPane.add(namePanel, BorderLayout.CENTER);
472
473        // locate the H5Property dialog
474        Point l = owner.getLocation();
475        l.x += 250;
476        l.y += 80;
477        setLocation(l);
478        pack();
479    }
480
481    public void actionPerformed(ActionEvent e) {
482        String cmd = e.getActionCommand();
483
484        if (cmd.equals("Ok")) {
485            if (dataView instanceof TableView) {
486                newObject = createFromTable();
487            }
488            else if (dataView instanceof ImageView) {
489                newObject = createFromImage();
490            }
491            else if (dataView == null) {
492                newObject = createFromScratch();
493            }
494
495            if (newObject != null) {
496                dispose();
497            }
498        }
499        if (cmd.equals("Cancel")) {
500            newObject = null;
501            dispose();
502            ((Vector<Object>) groupList).setSize(0);
503        }
504        else if (cmd.equals("Show help")) {
505            if (helpDialog == null) {
506                createHelpDialog();
507            }
508            helpDialog.setVisible(true);
509        }
510        else if (cmd.equals("Hide help")) {
511            if (helpDialog != null) {
512                helpDialog.setVisible(false);
513            }
514        }
515        else if (cmd.equals("Set max size")) {
516            String strMax = maxSizeField.getText();
517            if (strMax == null || strMax.length() < 1) strMax = currentSizeField.getText();
518
519            String msg = JOptionPane.showInputDialog(this, "Enter max dimension sizes. \n"
520                    + "Use \"unlimited\" for unlimited dimension size.\n\n" + "For example,\n" + "    200 x 100\n"
521                    + "    100 x unlimited\n\n", strMax);
522
523            if (msg == null || msg.length() < 1)
524                maxSizeField.setText(currentSizeField.getText());
525            else
526                maxSizeField.setText(msg);
527
528            checkMaxSize();
529        }
530    }
531
532    @SuppressWarnings("unchecked")
533    public void itemStateChanged(ItemEvent e) {
534        Object source = e.getSource();
535
536        if (source.equals(classChoice)) {
537            int idx = classChoice.getSelectedIndex();
538            sizeChoice.setSelectedIndex(0);
539            endianChoice.setSelectedIndex(0);
540            stringLengthField.setEnabled(false);
541
542            if ((idx == 0) || (idx == 6)) { // INTEGER
543                sizeChoice.setEnabled(true);
544                endianChoice.setEnabled(isH5);
545                checkUnsigned.setEnabled(true);
546
547                if (sizeChoice.getItemCount() == 3) {
548                    sizeChoice.removeItem("32");
549                    sizeChoice.removeItem("64");
550                    sizeChoice.addItem("8");
551                    sizeChoice.addItem("16");
552                    sizeChoice.addItem("32");
553                    sizeChoice.addItem("64");
554                }
555            }
556            else if ((idx == 1) || (idx == 7)) { // FLOAT
557                sizeChoice.setEnabled(true);
558                endianChoice.setEnabled(isH5);
559                checkUnsigned.setEnabled(false);
560
561                if (sizeChoice.getItemCount() == 5) {
562                    sizeChoice.removeItem("16");
563                    sizeChoice.removeItem("8");
564                }
565            }
566            else if (idx == 2) { // CHAR
567                sizeChoice.setEnabled(false);
568                endianChoice.setEnabled(isH5);
569                checkUnsigned.setEnabled(true);
570            }
571            else if (idx == 3) { // STRING
572                sizeChoice.setEnabled(false);
573                endianChoice.setEnabled(false);
574                checkUnsigned.setEnabled(false);
575                stringLengthField.setEnabled(true);
576                stringLengthField.setText("String length");
577            }
578            else if (idx == 4) { // REFERENCE
579                sizeChoice.setEnabled(false);
580                endianChoice.setEnabled(false);
581                checkUnsigned.setEnabled(false);
582                stringLengthField.setEnabled(false);
583            }
584            else if (idx == 5) { // ENUM
585                sizeChoice.setEnabled(true);
586                checkUnsigned.setEnabled(true);
587                stringLengthField.setEnabled(true);
588                stringLengthField.setText("R=0,G=1,B=2,...");
589            }
590            else if (idx == 8) {
591                sizeChoice.setEnabled(false);
592                endianChoice.setEnabled(false);
593                checkUnsigned.setEnabled(false);
594                stringLengthField.setEnabled(false);
595            }
596        }
597        else if (source.equals(sizeChoice)) {
598            if (classChoice.getSelectedIndex() == 0) {
599                checkUnsigned.setEnabled(true);
600            }
601        }
602        else if (source.equals(rankChoice)) {
603            int rank = rankChoice.getSelectedIndex() + 1;
604            String currentSizeStr = "1";
605            String maxSizeStr = "0";
606
607            for (int i = 1; i < rank; i++) {
608                currentSizeStr += " x 1";
609                maxSizeStr += " x 0";
610            }
611
612            currentSizeField.setText(currentSizeStr);
613            maxSizeField.setText(maxSizeStr);
614
615            String currentStr = currentSizeField.getText();
616            int idx = currentStr.lastIndexOf("x");
617            String chunkStr = "1";
618
619            if (rank <= 1) {
620                chunkStr = currentStr;
621            }
622            else {
623                for (int i = 1; i < rank - 1; i++) {
624                    chunkStr += " x 1";
625                }
626                if (idx > 0) {
627                    chunkStr += " x " + currentStr.substring(idx + 1);
628                }
629            }
630
631            chunkSizeField.setText(chunkStr);
632        }
633        else if (source.equals(checkContinguous)) {
634            chunkSizeField.setEnabled(false);
635        }
636        else if (source.equals(checkChunked)) {
637            chunkSizeField.setEnabled(true);
638            String chunkStr = "";
639            StringTokenizer st = new StringTokenizer(currentSizeField.getText(), "x");
640            int rank = rankChoice.getSelectedIndex() + 1;
641            while (st.hasMoreTokens()) {
642                long l = Math.max(1, Long.valueOf(st.nextToken().trim()) / (2 * rank));
643                chunkStr += String.valueOf(l) + "x";
644            }
645            chunkStr = chunkStr.substring(0, chunkStr.lastIndexOf('x'));
646            chunkSizeField.setText(chunkStr);
647        }
648        else if (source.equals(checkCompression)) {
649            boolean isCompressed = checkCompression.isSelected();
650
651            if (isCompressed && isH5) {
652                if (!checkChunked.isSelected()) {
653                    String currentStr = currentSizeField.getText();
654                    int idx = currentStr.lastIndexOf("x");
655                    String chunkStr = "1";
656
657                    int rank = rankChoice.getSelectedIndex() + 1;
658                    if (rank <= 1) {
659                        chunkStr = currentStr;
660                    }
661                    else {
662                        for (int i = 1; i < rank - 1; i++) {
663                            chunkStr += " x 1";
664                        }
665                        if (idx > 0) {
666                            chunkStr += " x " + currentStr.substring(idx + 1);
667                        }
668                    }
669
670                    chunkSizeField.setText(chunkStr);
671                }
672                compressionLevel.setEnabled(true);
673                checkContinguous.setEnabled(false);
674                checkChunked.setSelected(true);
675                chunkSizeField.setEnabled(true);
676            }
677            else {
678                compressionLevel.setEnabled(isCompressed);
679                checkContinguous.setEnabled(true);
680            }
681        }
682        else if (source.equals(checkFillValue)) {
683            fillValueField.setEnabled(checkFillValue.isSelected());
684        }
685    }
686
687    /** check is the max size is valid */
688    private void checkMaxSize() {
689        boolean isChunkNeeded = false;
690        String dimStr = currentSizeField.getText();
691        String maxStr = maxSizeField.getText();
692        StringTokenizer stMax = new StringTokenizer(maxStr, "x");
693        StringTokenizer stDim = new StringTokenizer(dimStr, "x");
694
695        if (stMax.countTokens() != stDim.countTokens()) {
696            toolkit.beep();
697            JOptionPane.showMessageDialog(this, "Wrong number of values in the max dimension size " + maxStr,
698                    getTitle(), JOptionPane.ERROR_MESSAGE);
699            maxSizeField.setText(null);
700            return;
701        }
702
703        int rank = stDim.countTokens();
704        long max = 0, dim = 0;
705        long[] maxdims = new long[rank];
706        for (int i = 0; i < rank; i++) {
707            String token = stMax.nextToken().trim();
708
709            token = token.toLowerCase();
710            if (token.startsWith("u")) {
711                max = -1;
712                isChunkNeeded = true;
713            }
714            else {
715                try {
716                    max = Long.parseLong(token);
717                }
718                catch (NumberFormatException ex) {
719                    toolkit.beep();
720                    JOptionPane.showMessageDialog(this, "Invalid max dimension size: " + maxStr, getTitle(),
721                            JOptionPane.ERROR_MESSAGE);
722                    maxSizeField.setText(null);
723                    return;
724                }
725            }
726
727            token = stDim.nextToken().trim();
728            try {
729                dim = Long.parseLong(token);
730            }
731            catch (NumberFormatException ex) {
732                toolkit.beep();
733                JOptionPane.showMessageDialog(this, "Invalid dimension size: " + dimStr, getTitle(),
734                        JOptionPane.ERROR_MESSAGE);
735                return;
736            }
737
738            if (max != -1 && max < dim) {
739                toolkit.beep();
740                JOptionPane.showMessageDialog(this, "Invalid max dimension size: " + maxStr, getTitle(),
741                        JOptionPane.ERROR_MESSAGE);
742                maxSizeField.setText(null);
743                return;
744            }
745            else if (max > dim) {
746                isChunkNeeded = true;
747            }
748
749            maxdims[i] = max;
750        } // for (int i = 0; i < rank; i++)
751
752        if (isH5) {
753            if (isChunkNeeded && !checkChunked.isSelected()) {
754                toolkit.beep();
755                JOptionPane.showMessageDialog(this, "Chunking is required for the max dimensions of " + maxStr,
756                        getTitle(), JOptionPane.ERROR_MESSAGE);
757                checkChunked.setSelected(true);
758            }
759        }
760        else {
761            for (int i = 1; i < rank; i++) {
762                if (maxdims[i] <= 0) {
763                    maxSizeField.setText(currentSizeField.getText());
764                    toolkit.beep();
765                    JOptionPane.showMessageDialog(this, "Only dim[0] can be unlimited." + maxStr, getTitle(),
766                            JOptionPane.ERROR_MESSAGE);
767                    return;
768                }
769            }
770        }
771    }
772
773    /** Creates a dialog to show the help information. */
774    private void createHelpDialog() {
775        helpDialog = new JDialog(this, "Create New Dataset");
776
777        JPanel contentPane = (JPanel) helpDialog.getContentPane();
778        contentPane.setLayout(new BorderLayout(5, 5));
779        contentPane.setBorder(BorderFactory.createEmptyBorder(15, 5, 5, 5));
780        int w = 500 + (ViewProperties.getFontSize() - 12) * 15;
781        int h = 400 + (ViewProperties.getFontSize() - 12) * 10;
782        contentPane.setPreferredSize(new Dimension(w, h));
783
784        JButton b = new JButton("  Ok  ");
785        b.addActionListener(this);
786        b.setActionCommand("Hide help");
787        JPanel tmpP = new JPanel();
788        tmpP.add(b);
789        contentPane.add(tmpP, BorderLayout.SOUTH);
790
791        JEditorPane infoPane = new JEditorPane();
792        infoPane.setEditable(false);
793        JScrollPane editorScrollPane = new JScrollPane(infoPane);
794        contentPane.add(editorScrollPane, BorderLayout.CENTER);
795
796        try {
797            URL url = null, url2 = null, url3 = null;
798            String rootPath = ViewProperties.getViewRoot();
799
800            try {
801                url = new URL("file:" + rootPath + "/lib/jhdfview.jar");
802            }
803            catch (java.net.MalformedURLException mfu) {
804                log.debug("help information:", mfu);
805            }
806
807            try {
808                url2 = new URL("file:" + rootPath + "/");
809            }
810            catch (java.net.MalformedURLException mfu) {
811                log.debug("help information:", mfu);
812            }
813
814            try {
815                url3 = new URL("file:" + rootPath + "/src/");
816            }
817            catch (java.net.MalformedURLException mfu) {
818                log.debug("help information:", mfu);
819            }
820
821            URL uu[] = { url, url2, url3 };
822            URLClassLoader cl = new URLClassLoader(uu);
823            URL u = cl.findResource("hdf/view/NewDatasetHelp.html");
824
825            if (u == null) {
826                u = ClassLoader.getSystemResource("hdf/view/NewDatasetHelp.html");
827            }
828
829            cl.close();
830            infoPane.setPage(u);
831            infoPane.addHyperlinkListener(this);
832        }
833        catch (Exception e) {
834            infoPane.setContentType("text/html");
835            StringBuffer buff = new StringBuffer();
836            buff.append("<html>");
837            buff.append("<body>");
838            buff.append("ERROR: cannot load help information.");
839            buff.append("</body>");
840            buff.append("</html>");
841            infoPane.setText(buff.toString());
842        }
843
844        Point l = helpDialog.getOwner().getLocation();
845        l.x += 50;
846        l.y += 80;
847        helpDialog.setLocation(l);
848        helpDialog.validate();
849        helpDialog.pack();
850    }
851
852    public void hyperlinkUpdate(HyperlinkEvent e) {
853        if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
854            JEditorPane pane = (JEditorPane) e.getSource();
855
856            if (e instanceof HTMLFrameHyperlinkEvent) {
857                HTMLFrameHyperlinkEvent evt = (HTMLFrameHyperlinkEvent) e;
858                HTMLDocument doc = (HTMLDocument) pane.getDocument();
859                doc.processHTMLFrameHyperlinkEvent(evt);
860            }
861            else {
862                try {
863                    pane.setPage(e.getURL());
864                }
865                catch (Throwable t) {
866                    log.debug("JEditorPane hyperlink:", t);
867                }
868            }
869        }
870    }
871
872    private HObject createFromScratch() {
873        String name = null;
874        Group pgroup = null;
875        boolean isVLen = false;
876        int rank = -1, gzip = -1, tclass = -1, tsize = -1, torder = -1, tsign = -1;
877        long dims[], maxdims[] = null, chunks[] = null;
878
879        name = nameField.getText().trim();
880        if ((name == null) || (name.length() < 1)) {
881            toolkit.beep();
882            JOptionPane
883            .showMessageDialog(this, "Dataset name is not specified.", getTitle(), JOptionPane.ERROR_MESSAGE);
884            return null;
885        }
886
887        if (name.indexOf(HObject.separator) >= 0) {
888            toolkit.beep();
889            JOptionPane.showMessageDialog(this, "Dataset name cannot contain path.", getTitle(),
890                    JOptionPane.ERROR_MESSAGE);
891            return null;
892        }
893
894        pgroup = (Group) groupList.get(parentChoice.getSelectedIndex());
895
896        if (pgroup == null) {
897            toolkit.beep();
898            JOptionPane.showMessageDialog(this, "Parent group is null.", getTitle(), JOptionPane.ERROR_MESSAGE);
899            return null;
900        }
901
902        // set datatype class
903        int idx = classChoice.getSelectedIndex();
904        if (idx == 0) {
905            tclass = Datatype.CLASS_INTEGER;
906            if (checkUnsigned.isSelected()) {
907                tsign = Datatype.SIGN_NONE;
908            }
909        }
910        else if (idx == 1) {
911            tclass = Datatype.CLASS_FLOAT;
912        }
913        else if (idx == 2) {
914            tclass = Datatype.CLASS_CHAR;
915            if (checkUnsigned.isSelected()) {
916                tsign = Datatype.SIGN_NONE;
917            }
918        }
919        else if (idx == 3) {
920            tclass = Datatype.CLASS_STRING;
921        }
922        else if (idx == 4) {
923            tclass = Datatype.CLASS_REFERENCE;
924        }
925        else if (idx == 5) {
926            tclass = Datatype.CLASS_ENUM;
927        }
928        else if (idx == 6) {
929            isVLen = true;
930            tclass = Datatype.CLASS_INTEGER;
931            if (checkUnsigned.isSelected()) {
932                tsign = Datatype.SIGN_NONE;
933            }
934        }
935        else if (idx == 7) {
936            isVLen = true;
937            tclass = Datatype.CLASS_FLOAT;
938        }
939        else if (idx == 8) {
940            isVLen = true;
941            tclass = Datatype.CLASS_STRING;
942        }
943
944        // set datatype size/order
945        idx = sizeChoice.getSelectedIndex();
946        if (tclass == Datatype.CLASS_STRING) {
947            if (isVLen) {
948                tsize = -1;
949            }
950            else {
951                int stringLength = 0;
952                try {
953                    stringLength = Integer.parseInt(stringLengthField.getText());
954                }
955                catch (NumberFormatException ex) {
956                    stringLength = -1;
957                }
958
959                if (stringLength <= 0) {
960                    toolkit.beep();
961                    JOptionPane.showMessageDialog(this, "Invalid string length: " + stringLengthField.getText(),
962                            getTitle(), JOptionPane.ERROR_MESSAGE);
963                    return null;
964                }
965                tsize = stringLength;
966            }
967        }
968        else if (tclass == Datatype.CLASS_ENUM) {
969            String enumStr = stringLengthField.getText();
970            if ((enumStr == null) || (enumStr.length() < 1) || enumStr.endsWith("...")) {
971                toolkit.beep();
972                JOptionPane.showMessageDialog(this, "Invalid member values: " + stringLengthField.getText(),
973                        getTitle(), JOptionPane.ERROR_MESSAGE);
974                return null;
975            }
976        }
977        else if (tclass == Datatype.CLASS_REFERENCE) {
978            tsize = 1;
979        }
980        else if (idx == 0) {
981            tsize = Datatype.NATIVE;
982        }
983        else if (tclass == Datatype.CLASS_FLOAT) {
984            tsize = idx * 4;
985        }
986        else {
987            tsize = 1 << (idx - 1);
988        }
989
990        if ((tsize == 8) && !isH5 && (tclass == Datatype.CLASS_INTEGER)) {
991            toolkit.beep();
992            JOptionPane.showMessageDialog(this, "HDF4 does not support 64-bit integer.", getTitle(),
993                    JOptionPane.ERROR_MESSAGE);
994            return null;
995        }
996
997        // set order
998        idx = endianChoice.getSelectedIndex();
999        if (idx == 0) {
1000            torder = Datatype.NATIVE;
1001        }
1002        else if (idx == 1) {
1003            torder = Datatype.ORDER_LE;
1004        }
1005        else {
1006            torder = Datatype.ORDER_BE;
1007        }
1008
1009        rank = rankChoice.getSelectedIndex() + 1;
1010        StringTokenizer st = new StringTokenizer(currentSizeField.getText(), "x");
1011        if (st.countTokens() < rank) {
1012            toolkit.beep();
1013            JOptionPane.showMessageDialog(this, "Number of values in the current dimension size is less than " + rank,
1014                    getTitle(), JOptionPane.ERROR_MESSAGE);
1015            return null;
1016        }
1017
1018        long l = 0;
1019        dims = new long[rank];
1020        String token = null;
1021        for (int i = 0; i < rank; i++) {
1022            token = st.nextToken().trim();
1023            try {
1024                l = Long.parseLong(token);
1025            }
1026            catch (NumberFormatException ex) {
1027                toolkit.beep();
1028                JOptionPane.showMessageDialog(this, "Invalid dimension size: " + currentSizeField.getText(),
1029                        getTitle(), JOptionPane.ERROR_MESSAGE);
1030                return null;
1031            }
1032
1033            if (l <= 0) {
1034                toolkit.beep();
1035                JOptionPane.showMessageDialog(this, "Dimension size must be greater than zero.", getTitle(),
1036                        JOptionPane.ERROR_MESSAGE);
1037                return null;
1038            }
1039
1040            dims[i] = l;
1041        }
1042
1043        String maxFieldStr = maxSizeField.getText();
1044        if (maxFieldStr != null && maxFieldStr.length() > 1) {
1045            st = new StringTokenizer(maxFieldStr, "x");
1046            if (st.countTokens() < rank) {
1047                toolkit.beep();
1048                JOptionPane.showMessageDialog(this, "Number of values in the max dimension size is less than " + rank,
1049                        getTitle(), JOptionPane.ERROR_MESSAGE);
1050                return null;
1051            }
1052
1053            l = 0;
1054            maxdims = new long[rank];
1055            for (int i = 0; i < rank; i++) {
1056                token = st.nextToken().trim();
1057
1058                token = token.toLowerCase();
1059                if (token.startsWith("u"))
1060                    l = -1;
1061                else {
1062                    try {
1063                        l = Long.parseLong(token);
1064                    }
1065                    catch (NumberFormatException ex) {
1066                        toolkit.beep();
1067                        JOptionPane.showMessageDialog(this, "Invalid max dimension size: " + maxSizeField.getText(),
1068                                getTitle(), JOptionPane.ERROR_MESSAGE);
1069                        return null;
1070                    }
1071                }
1072
1073                if (l < -1) {
1074                    toolkit.beep();
1075                    JOptionPane.showMessageDialog(this, "Dimension size cannot be less than -1.", getTitle(),
1076                            JOptionPane.ERROR_MESSAGE);
1077                    return null;
1078                }
1079                else if (l == 0) {
1080                    l = dims[i];
1081                }
1082
1083                maxdims[i] = l;
1084            }
1085        }
1086
1087        chunks = null;
1088        if (checkChunked.isSelected()) {
1089            st = new StringTokenizer(chunkSizeField.getText(), "x");
1090            if (st.countTokens() < rank) {
1091                toolkit.beep();
1092                JOptionPane.showMessageDialog(this, "Number of values in the chunk size is less than " + rank,
1093                        getTitle(), JOptionPane.ERROR_MESSAGE);
1094                return null;
1095            }
1096
1097            l = 0;
1098            chunks = new long[rank];
1099            for (int i = 0; i < rank; i++) {
1100                token = st.nextToken().trim();
1101                try {
1102                    l = Long.parseLong(token);
1103                }
1104                catch (NumberFormatException ex) {
1105                    toolkit.beep();
1106                    JOptionPane.showMessageDialog(this, "Invalid chunk dimension size: " + chunkSizeField.getText(),
1107                            getTitle(), JOptionPane.ERROR_MESSAGE);
1108                    return null;
1109                }
1110
1111                if (l < 1) {
1112                    toolkit.beep();
1113                    JOptionPane.showMessageDialog(this, "Chunk size cannot be less than 1.", getTitle(),
1114                            JOptionPane.ERROR_MESSAGE);
1115                    return null;
1116                }
1117
1118                chunks[i] = l;
1119            } // for (int i=0; i<rank; i++)
1120
1121            long tchunksize = 1, tdimsize = 1;
1122            for (int i = 0; i < rank; i++) {
1123                tchunksize *= chunks[i];
1124                tdimsize *= dims[i];
1125            }
1126
1127            if (tchunksize >= tdimsize) {
1128                toolkit.beep();
1129                int status = JOptionPane.showConfirmDialog(this, "Chunk size is equal/greater than the current size. "
1130                        + "\nAre you sure you want to set chunk size to " + chunkSizeField.getText() + "?", getTitle(),
1131                        JOptionPane.YES_NO_OPTION);
1132                if (status == JOptionPane.NO_OPTION) {
1133                    return null;
1134                }
1135            }
1136
1137            if (tchunksize == 1) {
1138                toolkit.beep();
1139                int status = JOptionPane.showConfirmDialog(this,
1140                        "Chunk size is one, which may cause large memory overhead for large dataset."
1141                                + "\nAre you sure you want to set chunk size to " + chunkSizeField.getText() + "?",
1142                                getTitle(), JOptionPane.YES_NO_OPTION);
1143                if (status == JOptionPane.NO_OPTION) {
1144                    return null;
1145                }
1146            }
1147
1148        } // if (checkChunked.isSelected())
1149
1150        if (checkCompression.isSelected()) {
1151            gzip = compressionLevel.getSelectedIndex();
1152        }
1153        else {
1154            gzip = 0;
1155        }
1156
1157        HObject obj = null;
1158        try {
1159            Datatype basedatatype = null;
1160            if (isVLen) {
1161                basedatatype = fileFormat.createDatatype(tclass, tsize, torder, tsign);
1162                tclass = Datatype.CLASS_VLEN;
1163            }
1164            Datatype datatype = fileFormat.createDatatype(tclass, tsize, torder, tsign, basedatatype);
1165            if (tclass == Datatype.CLASS_ENUM) {
1166                datatype.setEnumMembers(stringLengthField.getText());
1167            }
1168            String fillValue = null;
1169            if (fillValueField.isEnabled()) fillValue = fillValueField.getText();
1170
1171            obj = fileFormat.createScalarDS(name, pgroup, datatype, dims, maxdims, chunks, gzip, fillValue, null);
1172        }
1173        catch (Exception ex) {
1174            toolkit.beep();
1175            JOptionPane.showMessageDialog(this, ex, getTitle(), JOptionPane.ERROR_MESSAGE);
1176            return null;
1177        }
1178
1179        return obj;
1180    }
1181
1182    private HObject createFromTable() {
1183        HObject obj = null;
1184
1185        String name = null;
1186        Group pgroup = null;
1187
1188        name = nameField.getText();
1189        if (name == null) {
1190            toolkit.beep();
1191            JOptionPane
1192            .showMessageDialog(this, "Dataset name is not specified.", getTitle(), JOptionPane.ERROR_MESSAGE);
1193            return null;
1194        }
1195
1196        if (name.indexOf(HObject.separator) >= 0) {
1197            toolkit.beep();
1198            JOptionPane.showMessageDialog(this, "Dataset name cannot contain path.", getTitle(),
1199                    JOptionPane.ERROR_MESSAGE);
1200            return null;
1201        }
1202
1203        pgroup = (Group) groupList.get(parentChoice.getSelectedIndex());
1204        if (pgroup == null) {
1205            toolkit.beep();
1206            JOptionPane.showMessageDialog(this, "Parent group is null.", getTitle(), JOptionPane.ERROR_MESSAGE);
1207            return null;
1208        }
1209
1210        TableView tableView = (TableView) dataView;
1211        Object theData = tableView.getSelectedData();
1212        if (theData == null) {
1213            return null;
1214        }
1215
1216        int w = tableView.getTable().getSelectedColumnCount();
1217        int h = tableView.getTable().getSelectedRowCount();
1218        Dataset dataset = (Dataset) tableView.getDataObject();
1219        if (dataset instanceof ScalarDS) {
1220            ScalarDS sd = (ScalarDS) dataset;
1221            if (sd.isUnsigned()) {
1222                theData = Dataset.convertToUnsignedC(theData, null);
1223            }
1224        }
1225
1226        try {
1227            long[] dims = { h, w };
1228            obj = dataset.copy(pgroup, name, dims, theData);
1229        }
1230        catch (Exception ex) {
1231            toolkit.beep();
1232            JOptionPane.showMessageDialog(this, ex.getMessage(), getTitle(), JOptionPane.ERROR_MESSAGE);
1233            return null;
1234        }
1235
1236        return obj;
1237    }
1238
1239    private HObject createFromImage() {
1240        HObject obj = null;
1241        String name = null;
1242        Group pgroup = null;
1243
1244        name = nameField.getText();
1245        if (name == null) {
1246            toolkit.beep();
1247            JOptionPane
1248            .showMessageDialog(this, "Dataset name is not specified.", getTitle(), JOptionPane.ERROR_MESSAGE);
1249            return null;
1250        }
1251
1252        if (name.indexOf(HObject.separator) >= 0) {
1253            toolkit.beep();
1254            JOptionPane.showMessageDialog(this, "Dataset name cannot contain path.", getTitle(),
1255                    JOptionPane.ERROR_MESSAGE);
1256            return null;
1257        }
1258
1259        pgroup = (Group) groupList.get(parentChoice.getSelectedIndex());
1260        if (pgroup == null) {
1261            toolkit.beep();
1262            JOptionPane.showMessageDialog(this, "Parent group is null.", getTitle(), JOptionPane.ERROR_MESSAGE);
1263            return null;
1264        }
1265
1266        ImageView imageView = (ImageView) dataView;
1267        ScalarDS dataset = (ScalarDS) imageView.getDataObject();
1268        Object theData = imageView.getSelectedData();
1269
1270        if (theData == null) {
1271            return null;
1272        }
1273
1274        // in version 2.4, unsigned image data is converted to signed data
1275        // to write data, the data needs to converted back to unsigned.
1276        if (dataset.isUnsigned()) {
1277            theData = Dataset.convertToUnsignedC(theData, null);
1278        }
1279
1280        int w = imageView.getSelectedArea().width;
1281        int h = imageView.getSelectedArea().height;
1282
1283        try {
1284            long[] dims = null;
1285            if (isH5) {
1286                if (imageView.isTrueColor()) {
1287                    dims = new long[3];
1288                    if (imageView.isPlaneInterlace()) {
1289                        dims[0] = 3;
1290                        dims[1] = h;
1291                        dims[2] = w;
1292                    }
1293                    else {
1294                        dims[0] = h;
1295                        dims[1] = w;
1296                        dims[2] = 3;
1297                    }
1298                }
1299                else {
1300                    dims = new long[2];
1301                    dims[0] = h;
1302                    dims[1] = w;
1303                }
1304            }
1305            else {
1306                dims = new long[2];
1307                dims[0] = w;
1308                dims[1] = h;
1309            }
1310
1311            obj = dataset.copy(pgroup, name, dims, theData);
1312        }
1313        catch (Exception ex) {
1314            toolkit.beep();
1315            JOptionPane.showMessageDialog(this, ex.getMessage(), getTitle(), JOptionPane.ERROR_MESSAGE);
1316            return null;
1317        }
1318
1319        return obj;
1320    }
1321
1322    /**
1323     * Returns the new dataset created.
1324     * 
1325     * @return The new Dataset created
1326     */
1327    public DataFormat getObject() {
1328        return newObject;
1329    }
1330
1331    /**
1332     * Returns the parent group of the new dataset.
1333     * 
1334     * @return The parent group of the new Dataset
1335     */
1336    public Group getParentGroup() {
1337        return (Group) groupList.get(parentChoice.getSelectedIndex());
1338    }
1339}