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