    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 https://support.hdfgroup.org/products/licenses.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.dialog;
    016
    017import java.util.ArrayList;
    018import java.util.Iterator;
    019import java.util.List;
    020import org.eclipse.swt.SWT;
    021import org.eclipse.swt.events.DisposeEvent;
    022import org.eclipse.swt.events.DisposeListener;
    023import org.eclipse.swt.events.SelectionAdapter;
    024import org.eclipse.swt.events.SelectionEvent;
    025import org.eclipse.swt.events.VerifyEvent;
    026import org.eclipse.swt.events.VerifyListener;
    027import org.eclipse.swt.graphics.Point;
    028import org.eclipse.swt.graphics.Rectangle;
    029import org.eclipse.swt.layout.GridData;
    030import org.eclipse.swt.layout.GridLayout;
    031import org.eclipse.swt.widgets.Button;
    032import org.eclipse.swt.widgets.Combo;
    033import org.eclipse.swt.widgets.Composite;
    034import org.eclipse.swt.widgets.Display;
    035import org.eclipse.swt.widgets.Label;
    036import org.eclipse.swt.widgets.Shell;
    037import org.eclipse.swt.widgets.Text;
    038
    039import hdf.object.Group;
    040import hdf.object.HObject;
    041import hdf.view.Tools;
    042import hdf.view.ViewProperties;
    043
    044/**
    045 * NewGroupDialog shows a message dialog requesting user input for creating a new HDF4/5 group.
    046 *
    047 * @author Jordan T. Henderson
    048 * @version 2.4 12/30/2015
    049 */
    050public class NewGroupDialog extends NewDataObjectDialog {
    051
    052    /* Used to restore original size after click "less" button */
    053    private Point       originalSize;
    054
    055    private Text        nameField;
    056    private Text        compactField;
    057    private Text        indexedField;
    058
    059    private Combo       parentChoice;
    060    private Combo       orderFlags;
    061
    062    private Button      useCreationOrder;
    063    private Button      setLinkStorage;
    064    private Button      creationOrderHelpButton;
    065    private Button      storageTypeHelpButton;
    066    private Button      okButton;
    067    private Button      cancelButton;
    068    private Button      moreButton;
    069
    070    private Composite   moreOptionsComposite;
    071    private Composite   creationOrderComposite;
    072    private Composite   storageTypeComposite;
    073    private Composite   dummyComposite;
    074    private Composite   buttonComposite;
    075
    076    private List<Group> groupList;
    077
    078    private int         creationOrder;
    079
    080    private boolean     moreOptionsEnabled;
    081
    082    /**
    083     * Constructs a NewGroupDialog with specified list of possible parent groups.
    084     *
    085     * @param parent
    086     *            the parent shell of the dialog
    087     * @param pGroup
    088     *            the parent group which the new group is added to.
    089     * @param objs
    090     *            the list of all objects.
    091     */
    092    public NewGroupDialog(Shell parent, Group pGroup, List<?> objs) {
    093        super(parent, pGroup, objs);
    094
    095        moreOptionsEnabled = false;
    096    }
    097
    098    public void open() {
    099        Shell parent = getParent();
    100        shell = new Shell(parent, SWT.SHELL_TRIM | SWT.APPLICATION_MODAL);
    101        shell.setFont(curFont);
    102        shell.setText("New Group...");
    103        shell.setImage(ViewProperties.getHdfIcon());
    104        GridLayout layout = new GridLayout(1, false);
    105        layout.verticalSpacing = 0;
    106        shell.setLayout(layout);
    107
    108        Composite fieldComposite = new Composite(shell, SWT.NONE);
    109        fieldComposite.setLayout(new GridLayout(2, false));
    110        fieldComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
    111
    112        Label groupNameLabel = new Label(fieldComposite, SWT.LEFT);
    113        groupNameLabel.setFont(curFont);
    114        groupNameLabel.setText("Group name:");
    115
    116        nameField = new Text(fieldComposite, SWT.SINGLE | SWT.BORDER);
    117        nameField.setFont(curFont);
    118        GridData fieldData = new GridData(SWT.FILL, SWT.FILL, true, false);
    119        fieldData.minimumWidth = 250;
    120        nameField.setLayoutData(fieldData);
    121
    122        Label parentGroupLabel = new Label(fieldComposite, SWT.LEFT);
    123        parentGroupLabel.setFont(curFont);
    124        parentGroupLabel.setText("Parent group:");
    125        parentGroupLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
    126
    127        parentChoice = new Combo(fieldComposite, SWT.DROP_DOWN | SWT.BORDER | SWT.READ_ONLY);
    128        parentChoice.setFont(curFont);
    129        parentChoice.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
    130        parentChoice.addSelectionListener(new SelectionAdapter() {
    131            @Override
    132            public void widgetSelected(SelectionEvent e) {
    133                parentObj = groupList.get(parentChoice.getSelectionIndex());
    134            }
    135        });
    136
    137        groupList = new ArrayList<>();
    138        Object obj = null;
    139        Iterator<?> iterator = objList.iterator();
    140        while (iterator.hasNext()) {
    141            obj = iterator.next();
    142            if (obj instanceof Group) {
    143                Group g = (Group) obj;
    144                groupList.add(g);
    145                if (g.isRoot()) {
    146                    parentChoice.add(HObject.SEPARATOR);
    147                }
    148                else {
    149                    parentChoice.add(g.getPath() + g.getName() + HObject.SEPARATOR);
    150                }
    151            }
    152        }
    153
    154        if (((Group) parentObj).isRoot()) {
    155            parentChoice.select(parentChoice.indexOf(HObject.SEPARATOR));
    156        }
    157        else {
    158            parentChoice.select(parentChoice.indexOf(parentObj.getPath() +
    159                    parentObj.getName() + HObject.SEPARATOR));
    160        }
    161
    162        // Only add "More" button if file is H5 type
    163        if(isH5) {
    164            moreOptionsComposite = new Composite(shell, SWT.NONE);
    165            moreOptionsComposite.setLayout(new GridLayout(2, false));
    166            moreOptionsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
    167
    168            moreButton = new Button(moreOptionsComposite, SWT.PUSH);
    169            moreButton.setFont(curFont);
    170            moreButton.setText("   More   ");
    171            moreButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));
    172            moreButton.addSelectionListener(new SelectionAdapter() {
    173                @Override
    174                public void widgetSelected(SelectionEvent e) {
    175                    moreOptionsEnabled = !moreOptionsEnabled;
    176
    177                    if(moreOptionsEnabled) {
    178                        addMoreOptions();
    179                    }
    180                    else {
    181                        removeMoreOptions();
    182                    }
    183                }
    184            });
    185
    186            dummyComposite = new Composite(moreOptionsComposite, SWT.NONE);
    187            dummyComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
    188        }
    189        else {
    190            // Add dummy label to take up space as dialog is resized
    191            new Label(shell, SWT.NONE).setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
    192        }
    193
    194        buttonComposite = new Composite(shell, SWT.NONE);
    195        buttonComposite.setLayout(new GridLayout(2, true));
    196        buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
    197
    198        okButton = new Button(buttonComposite, SWT.PUSH);
    199        okButton.setFont(curFont);
    200        okButton.setText("   &OK   ");
    201        okButton.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
    202        okButton.addSelectionListener(new SelectionAdapter() {
    203            @Override
    204            public void widgetSelected(SelectionEvent e) {
    205                newObject = create();
    206                if (newObject != null) {
    207                    shell.dispose();
    208                }
    209            }
    210        });
    211
    212        cancelButton = new Button(buttonComposite, SWT.PUSH);
    213        cancelButton.setFont(curFont);
    214        cancelButton.setText(" &Cancel ");
    215        cancelButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, true, false));
    216        cancelButton.addSelectionListener(new SelectionAdapter() {
    217            @Override
    218            public void widgetSelected(SelectionEvent e) {
    219                newObject = null;
    220                shell.dispose();
    221            }
    222        });
    223
    224        shell.pack();
    225
    226        shell.addDisposeListener(new DisposeListener() {
    227            @Override
    228            public void widgetDisposed(DisposeEvent e) {
    229                if (curFont != null) curFont.dispose();
    230            }
    231        });
    232
    233        shell.setMinimumSize(shell.computeSize(SWT.DEFAULT, SWT.DEFAULT));
    234
    235        originalSize = shell.getSize();
    236
    237        Rectangle parentBounds = parent.getBounds();
    238        Point shellSize = shell.getSize();
    239        shell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2),
    240                          (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2));
    241
    242        shell.open();
    243
    244        Display display = shell.getDisplay();
    245        while (!shell.isDisposed())
    246            if (!display.readAndDispatch())
    247                display.sleep();
    248    }
    249
    250    private HObject create() {
    251        String name = null;
    252        Group pgroup = null;
    253        long gcpl = 0;
    254
    255        name = nameField.getText();
    256        if (name == null || name.length() == 0) {
    257            shell.getDisplay().beep();
    258            Tools.showError(shell, "Create", "Group name is not specified.");
    259            return null;
    260        }
    261
    262        if (name.indexOf(HObject.SEPARATOR) >= 0) {
    263            shell.getDisplay().beep();
    264            Tools.showError(shell, "Create", "Group name cannot contain path.");
    265            return null;
    266        }
    267
    268        pgroup = groupList.get(parentChoice.getSelectionIndex());
    269
    270        if (pgroup == null) {
    271            shell.getDisplay().beep();
    272            Tools.showError(shell, "Create", "Parent group is null.");
    273            return null;
    274        }
    275
    276        Group obj = null;
    277
    278        if (orderFlags != null && orderFlags.isEnabled()) {
    279            String order = orderFlags.getItem(orderFlags.getSelectionIndex());
    280            if (order.equals("Tracked"))
    281                creationOrder = Group.CRT_ORDER_TRACKED;
    282            else if (order.equals("Tracked+Indexed"))
    283                creationOrder = Group.CRT_ORDER_INDEXED;
    284        }
    285        else
    286            creationOrder = 0;
    287
    288        if ((orderFlags != null) && ((orderFlags.isEnabled()) || (setLinkStorage.getSelection()))) {
    289            int maxCompact = Integer.parseInt(compactField.getText());
    290            int minDense = Integer.parseInt(indexedField.getText());
    291
    292            if ((maxCompact <= 0) || (maxCompact > 65536) || (minDense > 65536)) {
    293                shell.getDisplay().beep();
    294                Tools.showError(shell, "Create", "Max Compact and Min Indexed should be > 0 and < 65536.");
    295                return null;
    296            }
    297
    298            if (maxCompact < minDense) {
    299                shell.getDisplay().beep();
    300                Tools.showError(shell, "Create", "Min Indexed should be <= Max Compact");
    301                return null;
    302            }
    303
    304            try {
    305                gcpl = fileFormat.createGcpl(creationOrder, maxCompact, minDense);
    306            }
    307            catch (Exception ex) {
    308                ex.printStackTrace();
    309            }
    310        }
    311
    312        try {
    313            if (isH5)
    314                obj = fileFormat.createGroup(name, pgroup, 0, gcpl);
    315            else
    316                obj = fileFormat.createGroup(name, pgroup);
    317        }
    318        catch (Exception ex) {
    319            shell.getDisplay().beep();
    320            Tools.showError(shell, "Create", ex.getMessage());
    321            return null;
    322        }
    323
    324        return obj;
    325    }
    326
    327    private void addMoreOptions() {
    328        moreButton.setText("   Less   ");
    329
    330        creationOrderComposite = new Composite(moreOptionsComposite, SWT.BORDER);
    331        creationOrderComposite.setLayout(new GridLayout(4, true));
    332        creationOrderComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
    333
    334        creationOrderHelpButton = new Button(creationOrderComposite, SWT.PUSH);
    335        creationOrderHelpButton.setImage(ViewProperties.getHelpIcon());
    336        creationOrderHelpButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
    337        creationOrderHelpButton.setToolTipText("Help on Creation Order");
    338        creationOrderHelpButton.addSelectionListener(new SelectionAdapter() {
    339            @Override
    340            public void widgetSelected(SelectionEvent e) {
    341                final String msg = "Use Creation Order allows the user to set the creation order \n"
    342                        + "of links in a group, so that tracking, indexing, and iterating over links\n"
    343                        + "in groups can be possible. \n\n"
    344                        + "If the order flag Tracked is selected, links in a group can now \n"
    345                        + "be explicitly tracked by the order that they were created. \n\n"
    346                        + "If the order flag Tracked+Indexed is selected, links in a group can \n"
    347                        + "now be explicitly tracked and indexed in the order that they were created. \n\n"
    348                        + "The default order in which links in a group are listed is alphanumeric-by-name. \n\n\n";
    349
    350                Tools.showInformation(shell, "Create", msg);
    351            }
    352        });
    353
    354        useCreationOrder = new Button(creationOrderComposite, SWT.CHECK);
    355        useCreationOrder.setFont(curFont);
    356        useCreationOrder.setText("Use Creation Order");
    357        useCreationOrder.addSelectionListener(new SelectionAdapter() {
    358            @Override
    359            public void widgetSelected(SelectionEvent e) {
    360                boolean isOrder = useCreationOrder.getSelection();
    361
    362                if (isOrder)
    363                    orderFlags.setEnabled(true);
    364                else
    365                    orderFlags.setEnabled(false);
    366            }
    367        });
    368
    369        Label label = new Label(creationOrderComposite, SWT.RIGHT);
    370        label.setFont(curFont);
    371        label.setText("Order Flags: ");
    372        label.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false));
    373
    374        orderFlags = new Combo(creationOrderComposite, SWT.DROP_DOWN | SWT.READ_ONLY);
    375        orderFlags.setFont(curFont);
    376        orderFlags.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));
    377        orderFlags.add("Tracked");
    378        orderFlags.add("Tracked+Indexed");
    379        orderFlags.select(orderFlags.indexOf("Tracked"));
    380        orderFlags.setEnabled(false);
    381
    382
    383        storageTypeComposite = new Composite(moreOptionsComposite, SWT.BORDER);
    384        storageTypeComposite.setLayout(new GridLayout(3, true));
    385        storageTypeComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
    386
    387        storageTypeHelpButton = new Button(storageTypeComposite, SWT.PUSH);
    388        storageTypeHelpButton.setImage(ViewProperties.getHelpIcon());
    389        storageTypeHelpButton.setToolTipText("Help on set Link Storage");
    390        storageTypeHelpButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
    391        storageTypeHelpButton.addSelectionListener(new SelectionAdapter() {
    392            @Override
    393            public void widgetSelected(SelectionEvent e) {
    394                final String msg = "Set Link Storage allows the users to explicitly set the storage  \n"
    395                        + "type of a group to be Compact or Indexed. \n\n"
    396                        + "Compact Storage: For groups with only a few links, compact link storage\n"
    397                        + "allows groups containing only a few links to take up much less space \n" + "in the file. \n\n"
    398                        + "Indexed Storage: For groups with large number of links, indexed link storage  \n"
    399                        + "provides a faster and more scalable method for storing and working with  \n"
    400                        + "large groups containing many links. \n\n"
    401                        + "The threshold for switching between the compact and indexed storage   \n"
    402                        + "formats is either set to default values or can be set by the user. \n\n"
    403                        + "<html><b>Max Compact</b></html> \n"
    404                        + "Max Compact is the maximum number of links to store in the group in a  \n"
    405                        + "compact format, before converting the group to the Indexed format. Groups \n"
    406                        + "that are in compact format and in which the number of links rises above \n"
    407                        + " this threshold are automatically converted to indexed format. \n\n"
    408                        + "<html><b>Min Indexed</b></html> \n"
    409                        + "Min Indexed is the minimum number of links to store in the Indexed format.   \n"
    410                        + "Groups which are in indexed format and in which the number of links falls    \n"
    411                        + "below this threshold are automatically converted to compact format. \n\n\n";
    412
    413                Tools.showInformation(shell, "Create", msg);
    414            }
    415        });
    416
    417        setLinkStorage = new Button(storageTypeComposite, SWT.CHECK);
    418        setLinkStorage.setFont(curFont);
    419        setLinkStorage.setText("Set Link Storage");
    420        setLinkStorage.addSelectionListener(new SelectionAdapter() {
    421            @Override
    422            public void widgetSelected(SelectionEvent e) {
    423                if (setLinkStorage.getSelection()) {
    424                    compactField.setEnabled(true);
    425                    indexedField.setEnabled(true);
    426                }
    427                else {
    428                    compactField.setText("8");
    429                    compactField.setEnabled(false);
    430                    indexedField.setText("6");
    431                    indexedField.setEnabled(false);
    432                }
    433            }
    434        });
    435
    436        Composite indexedComposite = new Composite(storageTypeComposite, SWT.NONE);
    437        indexedComposite.setLayout(new GridLayout(2, true));
    438        indexedComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true));
    439
    440        Label minLabel = new Label(indexedComposite, SWT.LEFT);
    441        minLabel.setFont(curFont);
    442        minLabel.setText("Min Indexed: ");
    443
    444        Label maxLabel = new Label(indexedComposite, SWT.LEFT);
    445        maxLabel.setFont(curFont);
    446        maxLabel.setText("Max Compact: ");
    447
    448        indexedField = new Text(indexedComposite, SWT.SINGLE | SWT.BORDER);
    449        indexedField.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
    450        indexedField.setFont(curFont);
    451        indexedField.setText("6");
    452        indexedField.setTextLimit(5);
    453        indexedField.setEnabled(false);
    454        indexedField.addVerifyListener(new VerifyListener() {
    455            @Override
    456            public void verifyText(VerifyEvent e) {
    457                String input = e.text;
    458
    459                char[] chars = new char[input.length()];
    460                input.getChars(0, chars.length, chars, 0);
    461                for (int i = 0; i < chars.length; i++) {
    462                   if (!('0' <= chars[i] && chars[i] <= '9')) {
    463                      e.doit = false;
    464                      return;
    465                   }
    466                }
    467            }
    468        });
    469
    470        compactField = new Text(indexedComposite, SWT.SINGLE | SWT.BORDER);
    471        compactField.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
    472        compactField.setFont(curFont);
    473        compactField.setText("8");
    474        compactField.setTextLimit(5);
    475        compactField.setEnabled(false);
    476        compactField.addVerifyListener(new VerifyListener() {
    477            @Override
    478            public void verifyText(VerifyEvent e) {
    479                String input = e.text;
    480
    481                char[] chars = new char[input.length()];
    482                input.getChars(0, chars.length, chars, 0);
    483                for (int i = 0; i < chars.length; i++) {
    484                   if (!('0' <= chars[i] && chars[i] <= '9')) {
    485                      e.doit = false;
    486                      return;
    487                   }
    488                }
    489            }
    490        });
    491
    492        shell.pack();
    493
    494        shell.setMinimumSize(shell.computeSize(SWT.DEFAULT, SWT.DEFAULT));
    495
    496        Rectangle parentBounds = shell.getParent().getBounds();
    497        Point shellSize = shell.getSize();
    498        shell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2),
    499                          (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2));
    500    }
    501
    502    private void removeMoreOptions() {
    503        moreButton.setText("   More   ");
    504
    505        creationOrderHelpButton.dispose();
    506        storageTypeHelpButton.dispose();
    507
    508        creationOrderComposite.dispose();
    509        storageTypeComposite.dispose();
    510
    511        shell.layout(true, true);
    512        shell.pack();
    513
    514        shell.setMinimumSize(originalSize);
    515        shell.setSize(originalSize);
    516
    517        Rectangle parentBounds = shell.getParent().getBounds();
    518        Point shellSize = shell.getSize();
    519        shell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2),
    520                          (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2));
    521    }
    522}