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.Dimension;
018import java.awt.Frame;
019import java.awt.GridLayout;
020import java.awt.Insets;
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.awt.event.KeyListener;
029import java.util.Iterator;
030import java.util.List;
031import java.util.Vector;
032
033import javax.swing.BorderFactory;
034import javax.swing.JButton;
035import javax.swing.JCheckBox;
036import javax.swing.JComboBox;
037import javax.swing.JDialog;
038import javax.swing.JLabel;
039import javax.swing.JOptionPane;
040import javax.swing.JPanel;
041import javax.swing.JTextField;
042import javax.swing.border.TitledBorder;
043import javax.swing.text.AttributeSet;
044import javax.swing.text.BadLocationException;
045import javax.swing.text.PlainDocument;
046
047import hdf.object.DataFormat;
048import hdf.object.FileFormat;
049import hdf.object.Group;
050import hdf.object.HObject;
051
052/**
053 * NewGroupDialog shows a message dialog requesting user input for creating a new HDF4/5 group.
054 */
055public class NewGroupDialog extends JDialog implements ActionListener, ItemListener, KeyListener {
056    private static final long serialVersionUID = 7340860373483987075L;
057
058    private final Toolkit toolkit;
059
060    private JTextField   nameField;
061    private JTextField   compactField;
062    private JTextField   indexedField;
063
064    @SuppressWarnings("rawtypes")
065    private JComboBox   parentChoice;
066    @SuppressWarnings("rawtypes")
067    private JComboBox   orderFlags;
068
069    private JCheckBox   useCreationOrder;
070    private JCheckBox   setLinkStorage;
071    private JButton     creationOrderHelpButton;
072    private JButton     storageTypeHelpButton;
073    private JButton     moreButton;
074
075    private List<Group> groupList;
076
077    private HObject     newObject;
078
079    private FileFormat  fileFormat;
080
081    private int         creationOrder;
082
083    private boolean     isH5;
084
085    private JPanel      useCreationOrderJPanel;
086
087    private JPanel      setLinkStorageJPanel;
088
089    private JPanel      labelPanel;
090
091    private JPanel      textPanel;
092
093    private JPanel      contentPane;
094
095    /**
096     * Constructs a NewGroupDialog with specified list of possible parent groups.
097     *
098     * @param owner
099     *            the owner of the input
100     * @param pGroup
101     *            the parent group which the new group is added to.
102     * @param objs
103     *            the list of all objects.
104     */
105    @SuppressWarnings({ "rawtypes", "unchecked" })
106    public NewGroupDialog(Frame owner, Group pGroup, List<?> objs) {
107        super(owner, "New Group...", true);
108
109        newObject = null;
110
111        fileFormat = pGroup.getFileFormat();
112        isH5 = pGroup.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5));
113        toolkit = Toolkit.getDefaultToolkit();
114
115        parentChoice = new JComboBox();
116        groupList = new Vector<Group>();
117        Object obj = null;
118        Iterator<?> iterator = objs.iterator();
119        while (iterator.hasNext()) {
120            obj = iterator.next();
121            if (obj instanceof Group) {
122                groupList.add((Group) obj);
123                Group g = (Group) obj;
124                if (g.isRoot()) {
125                    parentChoice.addItem(HObject.separator);
126                }
127                else {
128                    parentChoice.addItem(g.getPath() + g.getName() + HObject.separator);
129                }
130            }
131        }
132
133        if (pGroup.isRoot()) {
134            parentChoice.setSelectedItem(HObject.separator);
135        }
136        else {
137            parentChoice.setSelectedItem(pGroup.getPath() + pGroup.getName() + HObject.separator);
138        }
139
140        orderFlags = new JComboBox();
141        orderFlags.addItem("Tracked");
142        orderFlags.addItem("Tracked+Indexed");
143
144        contentPane = (JPanel) getContentPane();
145        contentPane.setLayout(new BorderLayout(5, 5));
146        contentPane.setBorder(BorderFactory.createEmptyBorder(15, 5, 5, 5));
147        int w = 400 + (ViewProperties.getFontSize() - 12) * 15;
148        int h = 150 + (ViewProperties.getFontSize() - 12) * 10;
149        contentPane.setPreferredSize(new Dimension(w, h));
150
151        JButton okButton = new JButton("   Ok   ");
152        okButton.setName("OK");
153        okButton.setActionCommand("Ok");
154        okButton.setMnemonic(KeyEvent.VK_O);
155        okButton.addActionListener(this);
156
157        JButton cancelButton = new JButton("Cancel");
158        cancelButton.setName("Cancel");
159        cancelButton.setMnemonic(KeyEvent.VK_C);
160        cancelButton.setActionCommand("Cancel");
161        cancelButton.addActionListener(this);
162
163        moreButton = new JButton("More");
164        moreButton.setName("More");
165        moreButton.addActionListener(this);
166
167        // set OK and CANCEL buttons
168        JPanel buttonPanel = new JPanel();
169        buttonPanel.add(okButton);
170        buttonPanel.add(cancelButton);
171        contentPane.add(buttonPanel, BorderLayout.SOUTH);
172
173        // set NAME and PARENT GROUP panel
174        JPanel namePanel = new JPanel();
175        namePanel.setLayout(new BorderLayout(5, 5));
176
177        labelPanel = new JPanel();
178        textPanel = new JPanel();
179
180        if (!isH5) {
181            labelPanel.setLayout(new GridLayout(2, 1));
182            labelPanel.add(new JLabel("Group name: "));
183            labelPanel.add(new JLabel("Parent group: "));
184            textPanel.setLayout(new GridLayout(2, 1));
185            textPanel.add(nameField = new JTextField());
186            textPanel.add(parentChoice);
187        }
188        else {
189            labelPanel.setLayout(new GridLayout(3, 1));
190            labelPanel.add(new JLabel("Group name: "));
191            labelPanel.add(new JLabel("Parent group: "));
192            labelPanel.add(moreButton); // if h5 format then add more button
193            textPanel.setLayout(new GridLayout(3, 1));
194            textPanel.add(nameField = new JTextField());
195            textPanel.add(parentChoice);
196            textPanel.add(new JLabel("")); // for more button
197        }
198        nameField.setName("groupname");
199        parentChoice.setName("groupparent");
200
201        creationOrderHelpButton = new JButton(ViewProperties.getHelpIcon());
202        creationOrderHelpButton.setToolTipText("Help on Creation Order");
203        creationOrderHelpButton.setMargin(new Insets(0, 0, 0, 0));
204        creationOrderHelpButton.addActionListener(this);
205        creationOrderHelpButton.setActionCommand("Help on Creation Order");
206
207        storageTypeHelpButton = new JButton(ViewProperties.getHelpIcon());
208        storageTypeHelpButton.setToolTipText("Help on set Link Storage");
209        storageTypeHelpButton.setMargin(new Insets(0, 0, 0, 0));
210        storageTypeHelpButton.addActionListener(this);
211        storageTypeHelpButton.setActionCommand("Help on set Link Storage");
212
213        namePanel.add(labelPanel, BorderLayout.WEST);
214
215        useCreationOrderJPanel = new JPanel();
216        useCreationOrderJPanel.setLayout(new GridLayout(1, 2));
217        useCreationOrderJPanel.setBorder(new TitledBorder(""));
218        useCreationOrderJPanel.add(useCreationOrder = new JCheckBox("Use Creation Order"));
219        useCreationOrder.addItemListener(this);
220        JPanel orderFlagsJPanel = new JPanel();
221        orderFlagsJPanel.setLayout(new GridLayout(1, 2));
222        orderFlagsJPanel.add(new JLabel("Order Flags: "));
223        orderFlagsJPanel.add(orderFlags);
224        orderFlags.setEnabled(false);
225        useCreationOrderJPanel.add(orderFlagsJPanel);
226
227        setLinkStorageJPanel = new JPanel();
228        setLinkStorageJPanel.setLayout(new GridLayout(1, 2));
229        setLinkStorageJPanel.setBorder(new TitledBorder(""));
230        setLinkStorageJPanel.add(setLinkStorage = new JCheckBox("Set Link Storage"));
231        setLinkStorage.addItemListener(this);
232        JPanel storageTypeJPanel = new JPanel();
233        storageTypeJPanel.setLayout(new GridLayout(2, 2));
234        storageTypeJPanel.add(new JLabel("Min Indexed: "));
235        storageTypeJPanel.add(new JLabel("Max Compact: "));
236        indexedField = new JTextField();
237        indexedField.addKeyListener(this);
238        storageTypeJPanel.add(indexedField);
239        indexedField.setDocument(new JTextFieldLimit(5));
240        indexedField.setText("6");
241        indexedField.setEnabled(false);
242        compactField = new JTextField();
243        storageTypeJPanel.add(compactField);
244        compactField.addKeyListener(this);
245        compactField.setDocument(new JTextFieldLimit(5));
246        compactField.setText("8");
247        compactField.setEnabled(false);
248        setLinkStorageJPanel.add(storageTypeJPanel);
249
250        namePanel.add(textPanel, BorderLayout.CENTER);
251        contentPane.add(namePanel, BorderLayout.CENTER);
252
253        // locate the H5Property dialog
254        Point l = owner.getLocation();
255        l.x += 250;
256        l.y += 80;
257        setLocation(l);
258        validate();
259        pack();
260    }
261
262    public void actionPerformed(ActionEvent e) {
263        String cmd = e.getActionCommand();
264
265        if (cmd.equals("More")) {
266            moreButton.setText("Less");
267            int w = 500 + (ViewProperties.getFontSize() - 12) * 15;
268            int h = 280 + (ViewProperties.getFontSize() - 12) * 10;
269            contentPane.setPreferredSize(new Dimension(w, h));
270            labelPanel.setLayout(new GridLayout(5, 1));
271            labelPanel.add(creationOrderHelpButton);
272            labelPanel.add(storageTypeHelpButton);
273            textPanel.setLayout(new GridLayout(5, 1));
274            textPanel.add(useCreationOrderJPanel);
275            textPanel.add(setLinkStorageJPanel);
276            validate();
277            pack();
278        }
279
280        if (cmd.equals("Less")) {
281            moreButton.setText("More");
282            int w = 400 + (ViewProperties.getFontSize() - 12) * 15;
283            int h = 150 + (ViewProperties.getFontSize() - 12) * 10;
284            contentPane.setPreferredSize(new Dimension(w, h));
285            labelPanel.setLayout(new GridLayout(3, 1));
286            labelPanel.remove(creationOrderHelpButton);
287            labelPanel.remove(storageTypeHelpButton);
288            textPanel.setLayout(new GridLayout(3, 1));
289            textPanel.remove(useCreationOrderJPanel);
290            textPanel.remove(setLinkStorageJPanel);
291            useCreationOrder.setSelected(false);
292            setLinkStorage.setSelected(false);
293            validate();
294            pack();
295        }
296
297        if (cmd.equals("Help on Creation Order")) {
298            final String msg = "Use Creation Order allows the user to set the creation order \n"
299                    + "of links in a group, so that tracking, indexing, and iterating over links\n"
300                    + "in groups can be possible. \n\n"
301                    + "If the order flag Tracked is selected, links in a group can now \n"
302                    + "be explicitly tracked by the order that they were created. \n\n"
303                    + "If the order flag Tracked+Indexed is selected, links in a group can \n"
304                    + "now be explicitly tracked and indexed in the order that they were created. \n\n"
305                    + "The default order in which links in a group are listed is alphanumeric-by-name. \n\n\n";
306            JOptionPane.showMessageDialog(this, msg);
307        }
308
309        if (cmd.equals("Help on set Link Storage")) {
310            final String msg = "Set Link Storage allows the users to explicitly set the storage  \n"
311                    + "type of a group to be Compact or Indexed. \n\n"
312                    + "Compact Storage: For groups with only a few links, compact link storage\n"
313                    + "allows groups containing only a few links to take up much less space \n" + "in the file. \n\n"
314                    + "Indexed Storage: For groups with large number of links, indexed link storage  \n"
315                    + "provides a faster and more scalable method for storing and working with  \n"
316                    + "large groups containing many links. \n\n"
317                    + "The threshold for switching between the compact and indexed storage   \n"
318                    + "formats is either set to default values or can be set by the user. \n\n"
319                    + "<html><b>Max Compact</b></html> \n"
320                    + "Max Compact is the maximum number of links to store in the group in a  \n"
321                    + "compact format, before converting the group to the Indexed format. Groups \n"
322                    + "that are in compact format and in which the number of links rises above \n"
323                    + " this threshold are automatically converted to indexed format. \n\n"
324                    + "<html><b>Min Indexed</b></html> \n"
325                    + "Min Indexed is the minimum number of links to store in the Indexed format.   \n"
326                    + "Groups which are in indexed format and in which the number of links falls    \n"
327                    + "below this threshold are automatically converted to compact format. \n\n\n";
328            JOptionPane.showMessageDialog(this, msg);
329        }
330
331        if (cmd.equals("Ok")) {
332            newObject = create();
333            if (newObject != null) {
334                dispose();
335            }
336        }
337        if (cmd.equals("Cancel")) {
338            newObject = null;
339            dispose();
340        }
341    }
342
343    private HObject create() {
344        String name = null;
345        Group pgroup = null;
346        int gcpl = 0;
347
348        name = nameField.getText();
349        if (name == null) {
350            toolkit.beep();
351            JOptionPane.showMessageDialog(this, "Group name is not specified.", getTitle(), JOptionPane.ERROR_MESSAGE);
352            return null;
353        }
354
355        if (name.indexOf(HObject.separator) >= 0) {
356            toolkit.beep();
357            JOptionPane.showMessageDialog(this, "Group name cannot contain path.", getTitle(),
358                    JOptionPane.ERROR_MESSAGE);
359            return null;
360        }
361
362        pgroup = groupList.get(parentChoice.getSelectedIndex());
363
364        if (pgroup == null) {
365            toolkit.beep();
366            JOptionPane.showMessageDialog(this, "Parent group is null.", getTitle(), JOptionPane.ERROR_MESSAGE);
367            return null;
368        }
369
370        Group obj = null;
371
372        if (orderFlags.isEnabled()) {
373            String order = (String) orderFlags.getSelectedItem();
374            if (order.equals("Tracked"))
375                creationOrder = Group.CRT_ORDER_TRACKED;
376            else if (order.equals("Tracked+Indexed"))
377                creationOrder = Group.CRT_ORDER_INDEXED;
378        }
379        else
380            creationOrder = 0;
381
382        if ((orderFlags.isEnabled()) || (setLinkStorage.isSelected())) {
383            int maxCompact = Integer.parseInt(compactField.getText());
384            int minDense = Integer.parseInt(indexedField.getText());
385
386            if ((maxCompact <= 0) || (maxCompact > 65536) || (minDense > 65536)) {
387                toolkit.beep();
388                JOptionPane.showMessageDialog(this, "Max Compact and Min Indexed should be > 0 and < 65536.",
389                        getTitle(), JOptionPane.ERROR_MESSAGE);
390                return null;
391            }
392
393            if (maxCompact < minDense) {
394                toolkit.beep();
395                JOptionPane.showMessageDialog(this, "Min Indexed should be <= Max Compact", getTitle(),
396                        JOptionPane.ERROR_MESSAGE);
397                return null;
398            }
399
400            try {
401                gcpl = fileFormat.createGcpl(creationOrder, maxCompact, minDense);
402            }
403            catch (Exception ex) {
404                ex.printStackTrace();
405            }
406        }
407
408        try {
409            if (isH5)
410                obj = fileFormat.createGroup(name, pgroup, 0, gcpl);
411            else
412                obj = fileFormat.createGroup(name, pgroup);
413        }
414        catch (Exception ex) {
415            toolkit.beep();
416            JOptionPane.showMessageDialog(this, ex.getMessage(), getTitle(), JOptionPane.ERROR_MESSAGE);
417            return null;
418        }
419
420        return obj;
421    }
422
423    /**
424     * Returns the new group created.
425     *
426     * @return The new group created
427     */
428    public DataFormat getObject() {
429        return newObject;
430    }
431
432    /**
433     * Returns the parent group of the new group.
434     *
435     * @return The parent group of the new group
436     */
437    public Group getParentGroup() {
438        return groupList.get(parentChoice.getSelectedIndex());
439    }
440
441    public void itemStateChanged(ItemEvent e) {
442        Object source = e.getSource();
443
444        if (source.equals(useCreationOrder)) {
445            boolean isOrder = useCreationOrder.isSelected();
446
447            if (isOrder)
448                orderFlags.setEnabled(true);
449            else
450                orderFlags.setEnabled(false);
451        }
452
453        if (source.equals(setLinkStorage)) {
454            boolean setStorage = setLinkStorage.isSelected();
455
456            if (setStorage) {
457                compactField.setEnabled(true);
458                indexedField.setEnabled(true);
459            }
460            else {
461                compactField.setText("8");
462                compactField.setEnabled(false);
463                indexedField.setText("6");
464                indexedField.setEnabled(false);
465            }
466        }
467    }
468
469    // Setting the length of the text fields.
470    class JTextFieldLimit extends PlainDocument {
471        private static final long serialVersionUID = -5131438789797052658L;
472        private int limit;
473
474        JTextFieldLimit(int limit) {
475            super();
476            this.limit = limit;
477        }
478
479        JTextFieldLimit(int limit, boolean upper) {
480            super();
481            this.limit = limit;
482        }
483
484        public void insertString(int offset, String str, AttributeSet attr) throws BadLocationException {
485            if (str == null)
486                return;
487
488            if ((getLength() + str.length()) <= limit) {
489                super.insertString(offset, str, attr);
490            }
491        }
492    }
493
494    public void keyPressed(java.awt.event.KeyEvent arg0) {
495    }
496
497    public void keyReleased(java.awt.event.KeyEvent arg0) {
498    }
499
500    public void keyTyped(java.awt.event.KeyEvent arg0) {
501        char c = arg0.getKeyChar();
502        if (!Character.isDigit(c))
503            arg0.consume(); // prevent event propagation
504    }
505
506}