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 file COPYING.                     *
009 * COPYING can be found at the root of the source code distribution tree.    *
010 * If you do not have access to this file, you may request a copy from       *
011 * help@hdfgroup.org.                                                        *
012 ****************************************************************************/
013
014package hdf.view;
015
016import java.awt.BorderLayout;
017import java.awt.Color;
018import java.awt.Dimension;
019import java.awt.GridLayout;
020import java.awt.Point;
021import java.awt.Toolkit;
022import java.awt.event.ActionEvent;
023import java.awt.event.ActionListener;
024import java.awt.event.ItemEvent;
025import java.awt.event.ItemListener;
026import java.awt.event.KeyEvent;
027import java.util.Hashtable;
028import java.util.Iterator;
029import java.util.List;
030import java.util.StringTokenizer;
031import java.util.Vector;
032
033import javax.swing.BorderFactory;
034import javax.swing.ButtonGroup;
035import javax.swing.DefaultCellEditor;
036import javax.swing.JButton;
037import javax.swing.JCheckBox;
038import javax.swing.JComboBox;
039import javax.swing.JDialog;
040import javax.swing.JFrame;
041import javax.swing.JLabel;
042import javax.swing.JOptionPane;
043import javax.swing.JPanel;
044import javax.swing.JRadioButton;
045import javax.swing.JScrollPane;
046import javax.swing.JTable;
047import javax.swing.JTextField;
048import javax.swing.border.TitledBorder;
049import javax.swing.table.DefaultTableModel;
050import javax.swing.table.TableCellEditor;
051
052import hdf.object.CompoundDS;
053import hdf.object.DataFormat;
054import hdf.object.Dataset;
055import hdf.object.Datatype;
056import hdf.object.FileFormat;
057import hdf.object.Group;
058import hdf.object.HObject;
059
060/**
061 * NewTableDataDialog shows a message dialog requesting user input for creating
062 * a new HDF4/5 dataset.
063 *
064 * @author Peter X. Cao
065 * @version 2.4 9/6/2007
066 */
067public class NewTableDataDialog extends JDialog implements ActionListener, ItemListener {
068    private static final long     serialVersionUID = -6786877503226330821L;
069
070    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(NewTableDataDialog.class);
071
072    private static final String[] DATATYPE_NAMES   = {
073        "byte (8-bit)", // 0
074        "short (16-bit)", // 1
075        "int (32-bit)", // 2
076        "unsigned byte (8-bit)", // 3
077        "unsigned short (16-bit)", // 4
078        "unsigned int (32-bit)", // 5
079        "long (64-bit)", // 6
080        "float", // 7
081        "double", // 8
082        "string", // 9
083        "enum", // 10
084        "unsigned long (64-bit)" // 11
085    };
086
087    private FileFormat            fileformat;
088
089    @SuppressWarnings("rawtypes")
090    private JComboBox             parentChoice, nFieldBox, templateChoice;
091
092    /** a list of current groups */
093    private Vector<Object>        groupList, compoundDSList;
094
095    private HObject               newObject;
096
097    private final Toolkit         toolkit;
098
099    private int                   numberOfMembers;
100
101    private JTable                table;
102
103    private DefaultTableModel     tableModel;
104
105    private RowEditorModel        rowEditorModel;
106
107    private DefaultCellEditor     cellEditor;
108
109    private JTextField            nameField, currentSizeField, maxSizeField, chunkSizeField;
110    @SuppressWarnings("rawtypes")
111    private JComboBox             compressionLevel, rankChoice, memberTypeChoice;
112    private JCheckBox             checkCompression;
113    private JRadioButton          checkContinguous, checkChunked;
114
115    /**
116     * Constructs NewTableDataDialog with specified list of possible parent
117     * groups.
118     *
119     * @param owner
120     *            the owner of the input
121     * @param pGroup
122     *            the parent group which the new group is added to.
123     * @param objs
124     *            the list of all objects.
125     */
126    @SuppressWarnings({ "unchecked", "rawtypes" })
127    public NewTableDataDialog(JFrame owner, Group pGroup, List<?> objs) {
128        super(owner, "New Compound Dataset...", true);
129
130        newObject = null;
131        numberOfMembers = 2;
132        fileformat = pGroup.getFileFormat();
133
134        memberTypeChoice = new JComboBox(DATATYPE_NAMES);
135        cellEditor = new DefaultCellEditor(memberTypeChoice);
136        rowEditorModel = new RowEditorModel(numberOfMembers, cellEditor);
137        String[] colNames = { "Name", "Datatype", "Array size / String length / Enum names" };
138        tableModel = new DefaultTableModel(colNames, numberOfMembers);
139        table = new JTable(tableModel) {
140            private static final long serialVersionUID = 7141605060652738476L;
141            RowEditorModel            rm               = rowEditorModel;
142
143            @Override
144            public TableCellEditor getCellEditor(int row, int col) {
145                TableCellEditor cellEditor = rm.getEditor(row);
146
147                if ((cellEditor == null) || !(col == 1)) {
148                    cellEditor = super.getCellEditor(row, col);
149                }
150
151                return cellEditor;
152            }
153        };
154        table.setName("CompoundDataset");
155        table.setRowSelectionAllowed(false);
156        table.setColumnSelectionAllowed(false);
157
158        // set cell height for large fonts
159        int cellRowHeight = Math.max(16, table.getFontMetrics(table.getFont()).getHeight());
160        table.setRowHeight(cellRowHeight);
161
162        toolkit = Toolkit.getDefaultToolkit();
163
164        parentChoice = new JComboBox();
165        String[] memberSizes = new String[100];
166        for (int i = 0; i < 100; i++) {
167            memberSizes[i] = String.valueOf(i + 1);
168        }
169
170        nFieldBox = new JComboBox(memberSizes);
171        nFieldBox.setName("numbermembers");
172        nFieldBox.setEditable(true);
173        nFieldBox.addActionListener(this);
174        nFieldBox.setActionCommand("Change number of members");
175        nFieldBox.setSelectedItem(String.valueOf(numberOfMembers));
176
177        groupList = new Vector<Object>(objs.size());
178        Object obj = null;
179        Iterator<?> iterator = objs.iterator();
180
181        compoundDSList = new Vector<Object>(objs.size());
182
183        while (iterator.hasNext()) {
184            obj = iterator.next();
185            if (obj instanceof Group) {
186                Group g = (Group) obj;
187                groupList.add(obj);
188                if (g.isRoot()) {
189                    parentChoice.addItem(HObject.separator);
190                }
191                else {
192                    parentChoice.addItem(g.getPath() + g.getName() + HObject.separator);
193                }
194            }
195            else if (obj instanceof CompoundDS) {
196                compoundDSList.add(obj);
197            }
198        }
199
200        templateChoice = new JComboBox(compoundDSList);
201        templateChoice.setName("templateChoice");
202        templateChoice.setSelectedIndex(-1);
203        templateChoice.addItemListener(this);
204
205        if (pGroup.isRoot()) {
206            parentChoice.setSelectedItem(HObject.separator);
207        }
208        else {
209            parentChoice.setSelectedItem(pGroup.getPath() + pGroup.getName() + HObject.separator);
210        }
211
212        JPanel contentPane = (JPanel) getContentPane();
213        contentPane.setLayout(new BorderLayout(5, 5));
214        contentPane.setBorder(BorderFactory.createEmptyBorder(15, 5, 5, 5));
215        int w = 700 + (ViewProperties.getFontSize() - 12) * 15;
216        int h = 500 + (ViewProperties.getFontSize() - 12) * 10;
217        contentPane.setPreferredSize(new Dimension(w, h));
218
219        JButton okButton = new JButton("   Ok   ");
220        okButton.setName("OK");
221        okButton.setActionCommand("Ok");
222        okButton.setMnemonic(KeyEvent.VK_O);
223        okButton.addActionListener(this);
224
225        JButton cancelButton = new JButton("Cancel");
226        cancelButton.setName("Cancel");
227        cancelButton.setMnemonic(KeyEvent.VK_C);
228        cancelButton.setActionCommand("Cancel");
229        cancelButton.addActionListener(this);
230
231        // set NAME and PARENT GROUP panel
232        JPanel namePanel = new JPanel();
233        namePanel.setLayout(new BorderLayout(5, 5));
234        JPanel tmpP = new JPanel();
235        tmpP.setLayout(new GridLayout(3, 1));
236        tmpP.add(new JLabel("   Dataset name: "));
237        tmpP.add(new JLabel("   Parent group: "));
238        tmpP.add(new JLabel("Import template: "));
239        namePanel.add(tmpP, BorderLayout.WEST);
240        tmpP = new JPanel();
241        tmpP.setLayout(new GridLayout(3, 1));
242        tmpP.add(nameField = new JTextField());
243        nameField.setName("datasetname");
244        tmpP.add(parentChoice);
245        tmpP.add(templateChoice);
246        namePanel.add(tmpP, BorderLayout.CENTER);
247
248        // set DATATSPACE
249        JPanel spacePanel = new JPanel();
250        spacePanel.setLayout(new GridLayout(2, 3, 15, 3));
251        TitledBorder border = new TitledBorder("Dataspace");
252        border.setTitleColor(Color.blue);
253        spacePanel.setBorder(border);
254
255        rankChoice = new JComboBox();
256        for (int i = 1; i < 33; i++) {
257            rankChoice.addItem(String.valueOf(i));
258        }
259        rankChoice.setSelectedIndex(0);
260
261        currentSizeField = new JTextField("1");
262        maxSizeField = new JTextField("0");
263        spacePanel.add(new JLabel("No. of dimensions"));
264        spacePanel.add(new JLabel("Current size"));
265        spacePanel.add(new JLabel("Max size (-1 for unlimited)"));
266        spacePanel.add(rankChoice);
267        spacePanel.add(currentSizeField);
268        spacePanel.add(maxSizeField);
269
270        // set storage layout and data compression
271        JPanel layoutPanel = new JPanel();
272        layoutPanel.setLayout(new BorderLayout());
273        border = new TitledBorder("Data Layout and Compression");
274        border.setTitleColor(Color.BLUE);
275        layoutPanel.setBorder(border);
276
277        checkContinguous = new JRadioButton("Contiguous");
278        checkContinguous.setSelected(true);
279        checkChunked = new JRadioButton("Chunked");
280        ButtonGroup bgroup = new ButtonGroup();
281        bgroup.add(checkChunked);
282        bgroup.add(checkContinguous);
283        chunkSizeField = new JTextField("1");
284        chunkSizeField.setEnabled(false);
285        checkCompression = new JCheckBox("gzip");
286
287        compressionLevel = new JComboBox();
288        for (int i = 0; i < 10; i++) {
289            compressionLevel.addItem(String.valueOf(i));
290        }
291        compressionLevel.setSelectedIndex(6);
292        compressionLevel.setEnabled(false);
293
294        tmpP = new JPanel();
295        tmpP.setLayout(new GridLayout(2, 1));
296        tmpP.add(new JLabel("Storage layout:  "));
297        tmpP.add(new JLabel("Compression:  "));
298        layoutPanel.add(tmpP, BorderLayout.WEST);
299
300        tmpP = new JPanel();
301        tmpP.setLayout(new GridLayout(2, 1));
302
303        JPanel tmpP0 = new JPanel();
304        tmpP0.setLayout(new GridLayout(1, 2));
305        tmpP0.add(checkContinguous);
306
307        JPanel tmpP00 = new JPanel();
308        tmpP00.setLayout(new GridLayout(1, 3));
309        tmpP00.add(checkChunked);
310        tmpP00.add(new JLabel("          Size: "));
311        tmpP00.add(chunkSizeField);
312        tmpP0.add(tmpP00);
313
314        tmpP.add(tmpP0);
315
316        tmpP0 = new JPanel();
317        tmpP0.setLayout(new GridLayout(1, 7));
318        tmpP0.add(checkCompression);
319        tmpP0.add(new JLabel("      Level: "));
320        tmpP0.add(compressionLevel);
321        tmpP0.add(new JLabel(""));
322        tmpP0.add(new JLabel(""));
323        tmpP0.add(new JLabel(""));
324        tmpP0.add(new JLabel(""));
325        tmpP.add(tmpP0);
326
327        layoutPanel.add(tmpP, BorderLayout.CENTER);
328
329        // add name, space and layout panels
330        tmpP = new JPanel();
331        tmpP.setLayout(new BorderLayout(5, 5));
332        tmpP.add(namePanel, BorderLayout.NORTH);
333        tmpP.add(spacePanel, BorderLayout.CENTER);
334        tmpP.add(layoutPanel, BorderLayout.SOUTH);
335
336        contentPane.add(tmpP, BorderLayout.NORTH);
337
338        // add field table
339        tmpP = new JPanel();
340        tmpP.setLayout(new BorderLayout(5, 5));
341        tmpP0 = new JPanel();
342        tmpP0.setLayout(new BorderLayout(5, 5));
343        tmpP0.add(new JLabel(" Number of Members:"), BorderLayout.WEST);
344        tmpP0.add(nFieldBox, BorderLayout.CENTER);
345        tmpP.add(tmpP0, BorderLayout.NORTH);
346        JScrollPane scroller = new JScrollPane(table);
347        border = new TitledBorder("Compound Datatype Properties");
348        border.setTitleColor(Color.BLUE);
349        tmpP.setBorder(border);
350        tmpP.add(scroller, BorderLayout.CENTER);
351        contentPane.add(tmpP, BorderLayout.CENTER);
352
353        // set OK and CANCEL buttons
354        JPanel buttonPanel = new JPanel();
355        buttonPanel.add(okButton);
356        buttonPanel.add(cancelButton);
357        contentPane.add(buttonPanel, BorderLayout.SOUTH);
358
359        rankChoice.addItemListener(this);
360        checkCompression.addItemListener(this);
361        checkContinguous.addItemListener(this);
362        checkChunked.addItemListener(this);
363        memberTypeChoice.addItemListener(this);
364
365        // locate the H5Property dialog
366        Point l = owner.getLocation();
367        l.x += 250;
368        l.y += 120;
369        setLocation(l);
370        validate();
371        pack();
372    }
373
374    public void actionPerformed(ActionEvent e) {
375        String cmd = e.getActionCommand();
376
377        if (cmd.equals("Ok")) {
378            try {
379                newObject = createCompoundDS();
380            }
381            catch (Exception ex) {
382                JOptionPane.showMessageDialog(this, ex, getTitle(), JOptionPane.ERROR_MESSAGE);
383            }
384
385            if (newObject != null) {
386                dispose();
387            }
388        }
389        else if (cmd.equals("Cancel")) {
390            newObject = null;
391            dispose();
392            (groupList).setSize(0);
393        }
394        else if (cmd.equals("Change number of members")) {
395            int n = 0;
396
397            try {
398                n = Integer.valueOf((String) nFieldBox.getSelectedItem()).intValue();
399            }
400            catch (Exception ex) {
401                log.debug("Change number of members:", ex);
402            }
403
404            if (n == numberOfMembers) {
405                return;
406            }
407
408            tableModel.setRowCount(n);
409            for (int i = numberOfMembers; i < n; i++) {
410                rowEditorModel.addEditorForRow(i, cellEditor);
411            }
412            numberOfMembers = n;
413        }
414    }
415
416    public void itemStateChanged(ItemEvent e) {
417        Object source = e.getSource();
418
419        if (source.equals(rankChoice)) {
420            int rank = (int)rankChoice.getSelectedIndex() + 1;
421            String currentSizeStr = "1";
422            String maxSizeStr = "0";
423
424            for (int i = 1; i < rank; i++) {
425                currentSizeStr += " x 1";
426                maxSizeStr += " x 0";
427            }
428
429            currentSizeField.setText(currentSizeStr);
430            maxSizeField.setText(maxSizeStr);
431
432            String currentStr = currentSizeField.getText();
433            int idx = currentStr.lastIndexOf("x");
434            String chunkStr = "1";
435
436            if (rank <= 1) {
437                chunkStr = currentStr;
438            }
439            else {
440                for (int i = 1; i < rank - 1; i++) {
441                    chunkStr += " x 1";
442                }
443                if (idx > 0) {
444                    chunkStr += " x " + currentStr.substring(idx + 1);
445                }
446            }
447
448            chunkSizeField.setText(chunkStr);
449        }
450        else if (source.equals(checkContinguous)) {
451            chunkSizeField.setEnabled(false);
452        }
453        else if (source.equals(checkChunked)) {
454            chunkSizeField.setEnabled(true);
455            String currentStr = currentSizeField.getText();
456            int idx = currentStr.lastIndexOf("x");
457            String chunkStr = "1";
458
459            int rank = (int)rankChoice.getSelectedIndex() + 1;
460            if (rank <= 1) {
461                chunkStr = currentStr;
462            }
463            else {
464                for (int i = 1; i < rank - 1; i++) {
465                    chunkStr += " x 1";
466                }
467                if (idx > 0) {
468                    chunkStr += " x " + currentStr.substring(idx + 1);
469                }
470            }
471
472            chunkSizeField.setText(chunkStr);
473        }
474        else if (source.equals(checkCompression)) {
475            boolean isCompressed = checkCompression.isSelected();
476
477            if (isCompressed) {
478                if (!checkChunked.isSelected()) {
479                    String currentStr = currentSizeField.getText();
480                    int idx = currentStr.lastIndexOf("x");
481                    String chunkStr = "1";
482
483                    int rank = (int)rankChoice.getSelectedIndex() + 1;
484                    if (rank <= 1) {
485                        chunkStr = currentStr;
486                    }
487                    else {
488                        for (int i = 1; i < rank - 1; i++) {
489                            chunkStr += " x 1";
490                        }
491                        if (idx > 0) {
492                            chunkStr += " x " + currentStr.substring(idx + 1);
493                        }
494                    }
495
496                    chunkSizeField.setText(chunkStr);
497                }
498                compressionLevel.setEnabled(true);
499                checkContinguous.setEnabled(false);
500                checkChunked.setSelected(true);
501                chunkSizeField.setEnabled(true);
502            }
503            else {
504                compressionLevel.setEnabled(false);
505                checkContinguous.setEnabled(true);
506            }
507        }
508        else if (source.equals(memberTypeChoice)) {
509            String item = (String) memberTypeChoice.getSelectedItem();
510            if ((item == null) || !item.equals("enum")) {
511                return;
512            }
513
514            int row = table.getSelectedRow();
515            table.setValueAt("mb1=0,mb=1,...", row, 2);
516        }
517        else if (source.equals(templateChoice)) {
518            Object obj = templateChoice.getSelectedItem();
519            if (!(obj instanceof CompoundDS)) {
520                return;
521            }
522
523            CompoundDS dset = (CompoundDS) obj;
524            int rank = dset.getRank();
525            if (rank < 1) {
526                dset.init();
527            }
528
529            rank = dset.getRank();
530            rankChoice.setSelectedIndex(rank - 1);
531            long[] dims = dset.getDims();
532            String[] mNames = dset.getMemberNames();
533            int[] mOrders = dset.getMemberOrders();
534            Datatype[] mTypes = dset.getMemberTypes();
535
536            String sizeStr = String.valueOf(dims[0]);
537            for (int i = 1; i < rank; i++) {
538                sizeStr += "x" + dims[i];
539            }
540            currentSizeField.setText(sizeStr);
541
542            try {
543                dset.getMetadata();
544            } // get chunking and compression info
545            catch (Exception ex) {
546                log.debug("get chunking and compression info:", ex);
547            }
548            long[] chunks = dset.getChunkSize();
549            if (chunks != null) {
550                checkChunked.setSelected(true);
551                sizeStr = String.valueOf(chunks[0]);
552                for (int i = 1; i < rank; i++) {
553                    sizeStr += "x" + chunks[i];
554                }
555                chunkSizeField.setText(sizeStr);
556            }
557
558            String compression = dset.getCompression();
559            if (compression != null) {
560                int clevel = -1;
561                int comp_pos = Dataset.compression_gzip_txt.length();
562                int idx = compression.indexOf(Dataset.compression_gzip_txt);
563                if (idx >= 0) {
564                    try {
565                        clevel = Integer.parseInt(compression.substring(idx + comp_pos, idx + comp_pos +1));
566                    }
567                    catch (NumberFormatException ex) {
568                        clevel = -1;
569                    }
570                }
571                if (clevel > 0) {
572                    checkCompression.setSelected(true);
573                    compressionLevel.setSelectedIndex(clevel);
574                }
575            }
576
577            numberOfMembers = dset.getMemberCount();
578            nFieldBox.setSelectedIndex(numberOfMembers - 1);
579            tableModel.setRowCount(numberOfMembers);
580            for (int i = 0; i < numberOfMembers; i++) {
581                rowEditorModel.addEditorForRow(i, cellEditor);
582
583                tableModel.setValueAt(mNames[i], i, 0);
584
585                int typeIdx = -1;
586                int tclass = mTypes[i].getDatatypeClass();
587                int tsize = mTypes[i].getDatatypeSize();
588                int tsigned = mTypes[i].getDatatypeSign();
589                if (tclass == Datatype.CLASS_ARRAY) {
590                    tclass = mTypes[i].getBasetype().getDatatypeClass();
591                    tsize = mTypes[i].getBasetype().getDatatypeSize();
592                    tsigned = mTypes[i].getBasetype().getDatatypeSign();
593                }
594                if (tclass == Datatype.CLASS_CHAR) {
595                    if (tsigned == Datatype.SIGN_NONE) {
596                        if (tsize == 1) {
597                            typeIdx = 3;
598                        }
599                    }
600                    else {
601                        if (tsize == 1) {
602                            typeIdx = 0;
603                        }
604                    }
605                }
606                if (tclass == Datatype.CLASS_INTEGER) {
607                    if (tsigned == Datatype.SIGN_NONE) {
608                        if (tsize == 1) {
609                            typeIdx = 3;
610                        }
611                        else if (tsize == 2) {
612                            typeIdx = 4;
613                        }
614                        else if (tsize == 4) {
615                            typeIdx = 5;
616                        }
617                        else {
618                            typeIdx = 11;
619                        }
620                    }
621                    else {
622                        if (tsize == 1) {
623                            typeIdx = 0;
624                        }
625                        else if (tsize == 2) {
626                            typeIdx = 1;
627                        }
628                        else if (tsize == 4) {
629                            typeIdx = 2;
630                        }
631                        else {
632                            typeIdx = 6;
633                        }
634                    }
635                }
636                else if (tclass == Datatype.CLASS_FLOAT) {
637                    if (tsize == 4) {
638                        typeIdx = 7;
639                    }
640                    else {
641                        typeIdx = 8;
642                    }
643                }
644                else if (tclass == Datatype.CLASS_STRING) {
645                    typeIdx = 9;
646                }
647                else if (tclass == Datatype.CLASS_ENUM) {
648                    typeIdx = 10;
649                }
650                if (typeIdx < 0) {
651                    continue;
652                }
653
654                memberTypeChoice.setSelectedIndex(typeIdx);
655                tableModel.setValueAt(memberTypeChoice.getSelectedItem(), i, 1);
656
657                if (tclass == Datatype.CLASS_STRING) {
658                    tableModel.setValueAt(String.valueOf(tsize), i, 2);
659                }
660                else if (tclass == Datatype.CLASS_ENUM) {
661                    tableModel.setValueAt(mTypes[i].getEnumMembers(), i, 2);
662                }
663                else {
664                    tableModel.setValueAt(String.valueOf(mOrders[i]), i, 2);
665                }
666
667            } // for (int i=0; i<numberOfMembers; i++)
668        } // else if (source.equals(templateChoice))
669    }
670
671    private HObject createCompoundDS() throws Exception {
672        HObject obj = null;
673        long dims[], maxdims[], chunks[];
674        int rank;
675
676        // stop editing the last selected cell
677        int row = table.getSelectedRow();
678        int col = table.getSelectedColumn();
679        if ((row >= 0) && (col > -0)) {
680            TableCellEditor ed = table.getCellEditor(row, col);
681            if (ed != null) {
682                ed.stopCellEditing();
683            }
684        }
685
686        maxdims = chunks = null;
687        String dname = nameField.getText();
688        if ((dname == null) || (dname.length() <= 0)) {
689            throw new IllegalArgumentException("Dataset name is empty");
690        }
691
692        Group pgroup = (Group) groupList.get(parentChoice.getSelectedIndex());
693        if (pgroup == null) {
694            throw new IllegalArgumentException("Invalid parent group");
695        }
696
697        int n = table.getRowCount();
698        if (n <= 0) {
699            return null;
700        }
701
702        String[] mNames = new String[n];
703        Datatype[] mDatatypes = new Datatype[n];
704        int[] mOrders = new int[n];
705
706        for (int i = 0; i < n; i++) {
707            String name = (String) table.getValueAt(i, 0);
708            if ((name == null) || (name.length() <= 0)) {
709                throw new IllegalArgumentException("Member name is empty");
710            }
711            mNames[i] = name;
712
713            int order = 1;
714            String orderStr = (String) table.getValueAt(i, 2);
715            if (orderStr != null) {
716                try {
717                    order = Integer.parseInt(orderStr);
718                }
719                catch (Exception ex) {
720                    log.debug("compound order:", ex);
721                }
722            }
723            mOrders[i] = order;
724
725            String typeName = (String) table.getValueAt(i, 1);
726            Datatype type = null;
727            if (DATATYPE_NAMES[0].equals(typeName)) {
728                type = fileformat.createDatatype(Datatype.CLASS_INTEGER, 1, Datatype.NATIVE, Datatype.NATIVE);
729            }
730            else if (DATATYPE_NAMES[1].equals(typeName)) {
731                type = fileformat.createDatatype(Datatype.CLASS_INTEGER, 2, Datatype.NATIVE, Datatype.NATIVE);
732            }
733            else if (DATATYPE_NAMES[2].equals(typeName)) {
734                type = fileformat.createDatatype(Datatype.CLASS_INTEGER, 4, Datatype.NATIVE, Datatype.NATIVE);
735            }
736            else if (DATATYPE_NAMES[3].equals(typeName)) {
737                type = fileformat.createDatatype(Datatype.CLASS_INTEGER, 1, Datatype.NATIVE, Datatype.SIGN_NONE);
738            }
739            else if (DATATYPE_NAMES[4].equals(typeName)) {
740                type = fileformat.createDatatype(Datatype.CLASS_INTEGER, 2, Datatype.NATIVE, Datatype.SIGN_NONE);
741            }
742            else if (DATATYPE_NAMES[5].equals(typeName)) {
743                type = fileformat.createDatatype(Datatype.CLASS_INTEGER, 4, Datatype.NATIVE, Datatype.SIGN_NONE);
744            }
745            else if (DATATYPE_NAMES[6].equals(typeName)) {
746                type = fileformat.createDatatype(Datatype.CLASS_INTEGER, 8, Datatype.NATIVE, Datatype.NATIVE);
747            }
748            else if (DATATYPE_NAMES[7].equals(typeName)) {
749                type = fileformat.createDatatype(Datatype.CLASS_FLOAT, 4, Datatype.NATIVE, Datatype.NATIVE);
750            }
751            else if (DATATYPE_NAMES[8].equals(typeName)) {
752                type = fileformat.createDatatype(Datatype.CLASS_FLOAT, 8, Datatype.NATIVE, Datatype.NATIVE);
753            }
754            else if (DATATYPE_NAMES[9].equals(typeName)) {
755                type = fileformat.createDatatype(Datatype.CLASS_STRING, order, Datatype.NATIVE, Datatype.NATIVE);
756            }
757            else if (DATATYPE_NAMES[10].equals(typeName)) { // enum
758                type = fileformat.createDatatype(Datatype.CLASS_ENUM, 4, Datatype.NATIVE, Datatype.NATIVE);
759                if ((orderStr == null) || (orderStr.length() < 1) || orderStr.endsWith("...")) {
760                    toolkit.beep();
761                    JOptionPane.showMessageDialog(this, "Invalid member values: " + orderStr, getTitle(),
762                            JOptionPane.ERROR_MESSAGE);
763                    return null;
764                }
765                else {
766                    type.setEnumMembers(orderStr);
767                }
768            }
769            else if (DATATYPE_NAMES[11].equals(typeName)) {
770                type = fileformat.createDatatype(Datatype.CLASS_INTEGER, 8, Datatype.NATIVE, Datatype.SIGN_NONE);
771            }
772            else {
773                throw new IllegalArgumentException("Invalid data type.");
774            }
775            mDatatypes[i] = type;
776        } // for (int i=0; i<n; i++)
777
778        rank = (int)rankChoice.getSelectedIndex() + 1;
779        StringTokenizer st = new StringTokenizer(currentSizeField.getText(), "x");
780        if (st.countTokens() < rank) {
781            toolkit.beep();
782            JOptionPane.showMessageDialog(this, "Number of values in the current dimension size is less than " + rank,
783                    getTitle(), JOptionPane.ERROR_MESSAGE);
784            return null;
785        }
786
787        long l = 0;
788        dims = new long[rank];
789        String token = null;
790        for (int i = 0; i < rank; i++) {
791            token = st.nextToken().trim();
792            try {
793                l = Long.parseLong(token);
794            }
795            catch (NumberFormatException ex) {
796                toolkit.beep();
797                JOptionPane.showMessageDialog(this, "Invalid dimension size: " + currentSizeField.getText(),
798                        getTitle(), JOptionPane.ERROR_MESSAGE);
799                return null;
800            }
801
802            if (l <= 0) {
803                toolkit.beep();
804                JOptionPane.showMessageDialog(this, "Dimension size must be greater than zero.", getTitle(),
805                        JOptionPane.ERROR_MESSAGE);
806                return null;
807            }
808
809            dims[i] = l;
810        }
811
812        st = new StringTokenizer(maxSizeField.getText(), "x");
813        if (st.countTokens() < rank) {
814            toolkit.beep();
815            JOptionPane.showMessageDialog(this, "Number of values in the max dimension size is less than " + rank,
816                    getTitle(), JOptionPane.ERROR_MESSAGE);
817            return null;
818        }
819
820        l = 0;
821        maxdims = new long[rank];
822        for (int i = 0; i < rank; i++) {
823            token = st.nextToken().trim();
824            try {
825                l = Long.parseLong(token);
826            }
827            catch (NumberFormatException ex) {
828                toolkit.beep();
829                JOptionPane.showMessageDialog(this, "Invalid max dimension size: " + maxSizeField.getText(),
830                        getTitle(), JOptionPane.ERROR_MESSAGE);
831                return null;
832            }
833
834            if (l < -1) {
835                toolkit.beep();
836                JOptionPane.showMessageDialog(this, "Dimension size cannot be less than -1.", getTitle(),
837                        JOptionPane.ERROR_MESSAGE);
838                return null;
839            }
840            else if (l == 0) {
841                l = dims[i];
842            }
843
844            maxdims[i] = l;
845        }
846
847        chunks = null;
848        if (checkChunked.isSelected()) {
849            st = new StringTokenizer(chunkSizeField.getText(), "x");
850            if (st.countTokens() < rank) {
851                toolkit.beep();
852                JOptionPane.showMessageDialog(this, "Number of values in the chunk size is less than " + rank,
853                        getTitle(), JOptionPane.ERROR_MESSAGE);
854                return null;
855            }
856
857            l = 0;
858            chunks = new long[rank];
859            token = null;
860            for (int i = 0; i < rank; i++) {
861                token = st.nextToken().trim();
862                try {
863                    l = Long.parseLong(token);
864                }
865                catch (NumberFormatException ex) {
866                    toolkit.beep();
867                    JOptionPane.showMessageDialog(this, "Invalid chunk dimension size: " + chunkSizeField.getText(),
868                            getTitle(), JOptionPane.ERROR_MESSAGE);
869                    return null;
870                }
871
872                if (l < 1) {
873                    toolkit.beep();
874                    JOptionPane.showMessageDialog(this, "Chunk size cannot be less than 1.", getTitle(),
875                            JOptionPane.ERROR_MESSAGE);
876                    return null;
877                }
878
879                chunks[i] = l;
880            } // for (int i=0; i<rank; i++)
881
882            long tchunksize = 1, tdimsize = 1;
883            for (int i = 0; i < rank; i++) {
884                tchunksize *= chunks[i];
885                tdimsize *= dims[i];
886            }
887
888            if (tchunksize >= tdimsize) {
889                toolkit.beep();
890                int status = JOptionPane.showConfirmDialog(this, "Chunk size is equal/greater than the current size. "
891                        + "\nAre you sure you want to set chunk size to " + chunkSizeField.getText() + "?", getTitle(),
892                        JOptionPane.YES_NO_OPTION);
893                if (status == JOptionPane.NO_OPTION) {
894                    return null;
895                }
896            }
897
898            if (tchunksize == 1) {
899                toolkit.beep();
900                int status = JOptionPane.showConfirmDialog(this,
901                        "Chunk size is one, which may cause large memory overhead for large dataset."
902                                + "\nAre you sure you want to set chunk size to " + chunkSizeField.getText() + "?",
903                                getTitle(), JOptionPane.YES_NO_OPTION);
904                if (status == JOptionPane.NO_OPTION) {
905                    return null;
906                }
907            }
908
909        } // if (checkChunked.isSelected())
910
911        int gzip = 0;
912        if (checkCompression.isSelected()) {
913            gzip = compressionLevel.getSelectedIndex();
914        }
915
916        if (checkChunked.isSelected()) {
917            obj = fileformat.createCompoundDS(dname, pgroup, dims, maxdims, chunks, gzip, mNames, mDatatypes, mOrders,
918                    null);
919        }
920        else {
921            obj = fileformat
922                    .createCompoundDS(dname, pgroup, dims, maxdims, null, -1, mNames, mDatatypes, mOrders, null);
923        }
924
925        return obj;
926    }
927
928    /**
929     * Returns the new dataset created.
930     *
931     * @return The new Dataset created
932     */
933    public DataFormat getObject() {
934        return newObject;
935    }
936
937    /**
938     * Returns the parent group of the new dataset.
939     *
940     * @return The parent group of the new Dataset
941     */
942    public Group getParentGroup() {
943        return (Group) groupList.get(parentChoice.getSelectedIndex());
944    }
945
946    private class RowEditorModel {
947        private Hashtable<Integer, TableCellEditor> data;
948
949        public RowEditorModel() {
950            data = new Hashtable<Integer, TableCellEditor>();
951        }
952
953        // all rows has the same cell editor
954        public RowEditorModel(int rows, TableCellEditor ed) {
955            data = new Hashtable<Integer, TableCellEditor>();
956            for (int i = 0; i < rows; i++) {
957                data.put(new Integer(i), ed);
958            }
959        }
960
961        public void addEditorForRow(int row, TableCellEditor e) {
962            data.put(new Integer(row), e);
963        }
964
965        public void removeEditorForRow(int row) {
966            data.remove(new Integer(row));
967        }
968
969        public TableCellEditor getEditor(int row) {
970            return (TableCellEditor) data.get(new Integer(row));
971        }
972    }
973}