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