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.Iterator;
028import java.util.List;
029import java.util.Vector;
030
031import javax.swing.BorderFactory;
032import javax.swing.JButton;
033import javax.swing.JCheckBox;
034import javax.swing.JComboBox;
035import javax.swing.JDialog;
036import javax.swing.JFrame;
037import javax.swing.JLabel;
038import javax.swing.JOptionPane;
039import javax.swing.JPanel;
040import javax.swing.JTextField;
041import javax.swing.border.TitledBorder;
042
043import hdf.object.DataFormat;
044import hdf.object.Datatype;
045import hdf.object.FileFormat;
046import hdf.object.Group;
047import hdf.object.HObject;
048
049/**
050 * NewDatatypeDialog shows a message dialog requesting user input for creating a
051 * new HDF5 datatype.
052 */
053public class NewDatatypeDialog extends JDialog
054implements ActionListener, ItemListener {
055    private static final long serialVersionUID = -1930736056916611522L;
056
057    private JTextField        nameField, stringLengthField;
058
059    @SuppressWarnings("rawtypes")
060    private JComboBox         parentChoice, classChoice, sizeChoice, endianChoice;
061
062    private JCheckBox         checkUnsigned;
063
064    private boolean           isH5;
065
066    /** a list of current groups */
067    private List<Object>      groupList;
068
069    private HObject           newObject;
070
071    private FileFormat        fileFormat;
072
073    private final Toolkit     toolkit;
074
075    /**
076     * Constructs a NewDatatypeDialog with specified list of possible parent
077     * groups.
078     *
079     * @param owner
080     *            the owner of the input
081     * @param pGroup
082     *            the parent group which the new group is added to.
083     * @param objs
084     *            the list of all objects.
085     */
086    @SuppressWarnings({ "rawtypes", "unchecked" })
087    public NewDatatypeDialog(JFrame owner, Group pGroup, List<?> objs) {
088        super(owner, "New Datatype...", true);
089
090        toolkit = Toolkit.getDefaultToolkit();
091
092        newObject = null;
093
094        fileFormat = pGroup.getFileFormat();
095        isH5 = pGroup.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5));
096
097        parentChoice = new JComboBox();
098        groupList = new Vector<Object>(objs.size());
099        Object obj = null;
100        Iterator<?> iterator = objs.iterator();
101        while (iterator.hasNext()) {
102            obj = iterator.next();
103            if (obj instanceof Group) {
104                Group g = (Group) obj;
105                groupList.add(obj);
106                if (g.isRoot()) {
107                    parentChoice.addItem(HObject.separator);
108                }
109                else {
110                    parentChoice.addItem(g.getPath() + g.getName() + HObject.separator);
111                }
112            }
113        }
114
115        if (pGroup.isRoot()) {
116            parentChoice.setSelectedItem(HObject.separator);
117        }
118        else {
119            parentChoice.setSelectedItem(pGroup.getPath() + pGroup.getName() + HObject.separator);
120        }
121
122        JPanel contentPane = (JPanel) getContentPane();
123        contentPane.setLayout(new BorderLayout(5, 5));
124        contentPane.setBorder(BorderFactory.createEmptyBorder(15, 5, 5, 5));
125        int w = 600 + (ViewProperties.getFontSize() - 12) * 15;
126        int h = 200 + (ViewProperties.getFontSize() - 12) * 10;
127        contentPane.setPreferredSize(new Dimension(w, h));
128
129        JButton okButton = new JButton("   Ok   ");
130        okButton.setName("OK");
131        okButton.setActionCommand("Ok");
132        okButton.setMnemonic(KeyEvent.VK_O);
133        okButton.addActionListener(this);
134
135        JButton cancelButton = new JButton("Cancel");
136        cancelButton.setName("Cancel");
137        cancelButton.setMnemonic(KeyEvent.VK_C);
138        cancelButton.setActionCommand("Cancel");
139        cancelButton.addActionListener(this);
140
141        // set OK and CANCEL buttons
142        JPanel buttonPanel = new JPanel();
143        buttonPanel.add(okButton);
144        buttonPanel.add(cancelButton);
145        contentPane.add(buttonPanel, BorderLayout.SOUTH);
146
147        // set NAME and PARENT GROUP panel
148        JPanel namePanel = new JPanel();
149        namePanel.setLayout(new BorderLayout(5, 5));
150        JPanel tmpP = new JPanel();
151        tmpP.setLayout(new GridLayout(2, 1));
152        tmpP.add(new JLabel("Datatype name: "));
153        tmpP.add(new JLabel("Parent group: "));
154        namePanel.add(tmpP, BorderLayout.WEST);
155        tmpP = new JPanel();
156        tmpP.setLayout(new GridLayout(2, 1));
157        nameField = new JTextField();
158        nameField.setName("dtname");
159        tmpP.add(nameField);
160        tmpP.add(parentChoice);
161        namePanel.add(tmpP, BorderLayout.CENTER);
162        contentPane.add(namePanel, BorderLayout.NORTH);
163
164        // set DATATYPE
165        JPanel typePanel = new JPanel();
166        typePanel.setLayout(new GridLayout(2, 4, 15, 3));
167        TitledBorder border = new TitledBorder("Datatype");
168        border.setTitleColor(Color.blue);
169        typePanel.setBorder(border);
170
171        stringLengthField = new JTextField("String length");
172        stringLengthField.setName("dtstringlen");
173        stringLengthField.setEnabled(false);
174
175        endianChoice = new JComboBox();
176        endianChoice.setName("dtendian");
177        classChoice = new JComboBox();
178        classChoice.setName("dtclass");
179        sizeChoice = new JComboBox();
180        sizeChoice.setName("dtsize");
181        endianChoice.setEnabled(isH5);
182
183        classChoice.addItem("INTEGER");
184        classChoice.addItem("FLOAT");
185        classChoice.addItem("CHAR");
186
187        if (isH5) {
188            classChoice.addItem("STRING");
189            classChoice.addItem("REFERENCE");
190            classChoice.addItem("VLEN_INTEGER");
191            classChoice.addItem("VLEN_FLOAT");
192            classChoice.addItem("VLEN_STRING");
193            sizeChoice.addItem("NATIVE");
194            endianChoice.addItem("NATIVE");
195            endianChoice.addItem("LITTLE ENDIAN");
196            endianChoice.addItem("BIG ENDIAN");
197        }
198        else {
199            sizeChoice.addItem("DEFAULT");
200            endianChoice.addItem("DEFAULT");
201            typePanel.add(new JLabel());
202        }
203        sizeChoice.addItem("8");
204        sizeChoice.addItem("16");
205        sizeChoice.addItem("32");
206        sizeChoice.addItem("64");
207
208        typePanel.add(new JLabel("Datatype class"));
209        typePanel.add(new JLabel("Size (bits)"));
210        typePanel.add(new JLabel("Byte ordering"));
211        checkUnsigned = new JCheckBox("Unsigned");
212        checkUnsigned.setName("dtchkunsigned");
213        typePanel.add(checkUnsigned);
214
215        typePanel.add(classChoice);
216        typePanel.add(sizeChoice);
217        typePanel.add(endianChoice);
218        typePanel.add(stringLengthField);
219
220        contentPane.add(typePanel, BorderLayout.CENTER);
221
222        classChoice.addItemListener(this);
223        sizeChoice.addItemListener(this);
224
225        // locate the H5Property dialog
226        Point l = owner.getLocation();
227        l.x += 250;
228        l.y += 100;
229        setLocation(l);
230        validate();
231        pack();
232    }
233
234    public void actionPerformed(ActionEvent e) {
235        Object source = e.getSource();
236        String cmd = e.getActionCommand();
237
238        if (cmd.equals("Ok")) {
239            newObject = createDatatype();
240
241            if (newObject != null) {
242                dispose();
243            }
244        }
245        if (cmd.equals("Cancel")) {
246            newObject = null;
247            dispose();
248        }
249    }
250
251    @SuppressWarnings("unchecked")
252    public void itemStateChanged(ItemEvent e) {
253        Object source = e.getSource();
254
255        if (source.equals(classChoice)) {
256            int idx = classChoice.getSelectedIndex();
257            sizeChoice.setSelectedIndex(0);
258            endianChoice.setSelectedIndex(0);
259            stringLengthField.setEnabled(false);
260
261            if ((idx == 0) || (idx == 5)) {
262                sizeChoice.setEnabled(true);
263                endianChoice.setEnabled(isH5);
264                checkUnsigned.setEnabled(true);
265
266                if (sizeChoice.getItemCount() == 3) {
267                    sizeChoice.removeItem("32");
268                    sizeChoice.removeItem("64");
269                    sizeChoice.addItem("8");
270                    sizeChoice.addItem("16");
271                    sizeChoice.addItem("32");
272                    sizeChoice.addItem("64");
273                }
274            }
275            else if ((idx == 1) || (idx == 6)) {
276                sizeChoice.setEnabled(true);
277                endianChoice.setEnabled(isH5);
278                checkUnsigned.setEnabled(false);
279
280                if (sizeChoice.getItemCount() == 5) {
281                    sizeChoice.removeItem("16");
282                    sizeChoice.removeItem("8");
283                }
284            }
285            else if (idx == 2) {
286                sizeChoice.setEnabled(false);
287                endianChoice.setEnabled(isH5);
288                checkUnsigned.setEnabled(true);
289            }
290            else if (idx == 3) {
291                sizeChoice.setEnabled(false);
292                endianChoice.setEnabled(false);
293                checkUnsigned.setEnabled(false);
294                stringLengthField.setEnabled(true);
295                stringLengthField.setText("String length");
296            }
297            else if (idx == 4) {
298                sizeChoice.setEnabled(false);
299                endianChoice.setEnabled(false);
300                checkUnsigned.setEnabled(false);
301                stringLengthField.setEnabled(false);
302            }
303            else if (idx == 7) {
304                sizeChoice.setEnabled(false);
305                endianChoice.setEnabled(false);
306                checkUnsigned.setEnabled(false);
307                stringLengthField.setEnabled(false);
308            }
309        }
310        else if (source.equals(sizeChoice)) {
311            if (classChoice.getSelectedIndex() == 0) {
312                checkUnsigned.setEnabled(true);
313            }
314        }
315    }
316
317    private HObject createDatatype() {
318        String name = null;
319        Group pgroup = null;
320        boolean isVLen = false;
321        int tclass = -1, tsize = -1, torder = -1, tsign = -1;
322        name = nameField.getText().trim();
323        if ((name == null) || (name.length() < 1)) {
324            toolkit.beep();
325            JOptionPane.showMessageDialog(this,
326                    "Datatype name is not specified.",
327                    getTitle(),
328                    JOptionPane.ERROR_MESSAGE);
329            return null;
330        }
331
332        if (name.indexOf(HObject.separator) >= 0) {
333            toolkit.beep();
334            JOptionPane.showMessageDialog(this,
335                    "Datatype name cannot contain path.",
336                    getTitle(),
337                    JOptionPane.ERROR_MESSAGE);
338            return null;
339        }
340
341        pgroup = (Group) groupList.get(parentChoice.getSelectedIndex());
342
343        if (pgroup == null) {
344            toolkit.beep();
345            JOptionPane.showMessageDialog(this,
346                    "Parent group is null.",
347                    getTitle(),
348                    JOptionPane.ERROR_MESSAGE);
349            return null;
350        }
351
352        // set datatype class
353        int idx = classChoice.getSelectedIndex();
354        if (idx == 0) {
355            tclass = Datatype.CLASS_INTEGER;
356            if (checkUnsigned.isSelected()) {
357                tsign = Datatype.SIGN_NONE;
358            }
359        }
360        else if (idx == 1) {
361            tclass = Datatype.CLASS_FLOAT;
362        }
363        else if (idx == 2) {
364            tclass = Datatype.CLASS_CHAR;
365            if (checkUnsigned.isSelected()) {
366                tsign = Datatype.SIGN_NONE;
367            }
368        }
369        else if (idx == 3) {
370            tclass = Datatype.CLASS_STRING;
371        }
372        else if (idx == 4) {
373            tclass = Datatype.CLASS_REFERENCE;
374        }
375        else if (idx == 5) {;
376            isVLen = true;
377            tclass = Datatype.CLASS_INTEGER;
378            if (checkUnsigned.isSelected()) {
379                tsign = Datatype.SIGN_NONE;
380            }
381        }
382        else if (idx == 6) {;
383            isVLen = true;
384            tclass = Datatype.CLASS_FLOAT;
385        }
386        else if (idx == 7) {
387            isVLen = true;
388            tclass = Datatype.CLASS_STRING;
389        }
390
391        // set datatype size/order
392        idx = sizeChoice.getSelectedIndex();
393        if (tclass == Datatype.CLASS_STRING) {
394            if (isVLen) {
395                tsize = -1;
396            }
397            else {
398                int stringLength = 0;
399                try {
400                    stringLength = Integer.parseInt(stringLengthField.getText());
401                }
402                catch (NumberFormatException ex) {
403                    stringLength = -1;
404                }
405
406                if (stringLength <= 0) {
407                    toolkit.beep();
408                    JOptionPane.showMessageDialog(this,
409                            "Invalid string length: " + stringLengthField.getText(),
410                            getTitle(),
411                            JOptionPane.ERROR_MESSAGE);
412                    return null;
413                }
414
415                tsize = stringLength;
416            }
417        }
418        else if (tclass == Datatype.CLASS_REFERENCE) {
419            tsize = 1;
420        }
421        else if (idx == 0) {
422            tsize = Datatype.NATIVE;
423        }
424        else if (tclass == Datatype.CLASS_FLOAT) {
425            tsize = idx * 4;
426        }
427        else {
428            tsize = 1 << (idx - 1);
429        }
430
431        if ((tsize == 8) && !isH5 && (tclass == Datatype.CLASS_INTEGER)) {
432            toolkit.beep();
433            JOptionPane.showMessageDialog(this,
434                    "HDF4 does not support 64-bit integer.",
435                    getTitle(),
436                    JOptionPane.ERROR_MESSAGE);
437            return null;
438        }
439
440        // set order
441        idx = endianChoice.getSelectedIndex();
442        if (idx == 0) {
443            torder = Datatype.NATIVE;
444        }
445        else if (idx == 1) {
446            torder = Datatype.ORDER_LE;
447        }
448        else {
449            torder = Datatype.ORDER_BE;
450        }
451
452        HObject obj = null;
453        try {
454            String fullPath = HObject.separator;
455            if (pgroup.isRoot()) {
456                fullPath += name;
457            }
458            else {
459                fullPath = pgroup.getPath() + HObject.separator + pgroup.getName() + HObject.separator + name;
460            }
461            Datatype basedatatype = null;
462            if (isVLen) {
463                basedatatype = fileFormat.createDatatype(tclass, tsize, torder, tsign);
464                tclass = Datatype.CLASS_VLEN;
465            }
466            Datatype datatype = fileFormat.createDatatype(tclass, tsize, torder, tsign, basedatatype, fullPath);
467            obj = datatype;
468        }
469        catch (Exception ex) {
470            toolkit.beep();
471            JOptionPane.showMessageDialog(this,
472                    ex,
473                    getTitle(),
474                    JOptionPane.ERROR_MESSAGE);
475            return null;
476        }
477
478        return obj;
479    }
480
481    /** @return the new dataset created. */
482    public DataFormat getObject() {
483        return newObject;
484    }
485
486    /** @return the parent group of the new dataset. */
487    public Group getParentGroup() {
488        return (Group) groupList.get(parentChoice.getSelectedIndex());
489    }
490}