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}