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.io.InputStream;
018import java.math.BigInteger;
019import java.net.URL;
020import java.net.URLClassLoader;
021import java.util.Iterator;
022import java.util.List;
023import java.util.Scanner;
024import java.util.StringTokenizer;
025
026import org.slf4j.Logger;
027import org.slf4j.LoggerFactory;
028
029import org.eclipse.swt.SWT;
030import org.eclipse.swt.browser.Browser;
031import org.eclipse.swt.events.DisposeEvent;
032import org.eclipse.swt.events.DisposeListener;
033import org.eclipse.swt.events.SelectionAdapter;
034import org.eclipse.swt.events.SelectionEvent;
035import org.eclipse.swt.graphics.Point;
036import org.eclipse.swt.graphics.Rectangle;
037import org.eclipse.swt.layout.GridData;
038import org.eclipse.swt.layout.GridLayout;
039import org.eclipse.swt.widgets.Button;
040import org.eclipse.swt.widgets.Combo;
041import org.eclipse.swt.widgets.Composite;
042import org.eclipse.swt.widgets.Dialog;
043import org.eclipse.swt.widgets.Display;
044import org.eclipse.swt.widgets.Label;
045import org.eclipse.swt.widgets.Shell;
046import org.eclipse.swt.widgets.Text;
047
048import hdf.object.Attribute;
049import hdf.object.Datatype;
050import hdf.object.FileFormat;
051import hdf.object.Group;
052import hdf.object.HObject;
053import hdf.object.MetaDataContainer;
054
055import hdf.view.Tools;
056import hdf.view.ViewProperties;
057
058/**
059 * NewStringAttributeDialog displays components for adding a new attribute.
060 *
061 * @author Jordan T. Henderson
062 * @version 2.4 1/7/2016
063 */
064public class NewStringAttributeDialog extends NewDataObjectDialog {
065
066    private static final Logger log = LoggerFactory.getLogger(NewStringAttributeDialog.class);
067
068    /** the default length of a string attribute */
069    public static final int   DEFAULT_STRING_ATTRIBUTE_LENGTH = 256;
070
071    /** TextField for entering the name of the dataset */
072    private Text              nameField;
073
074    /** TextField for entering the attribute value. */
075    private Text              valueField;
076
077    /** The Choice of the object list */
078    private Combo             objChoice;
079
080    private Button            h4GrAttrRadioButton;
081
082    private Label             arrayLengthLabel;
083
084    /** If the attribute should be attached to a hdf4 object */
085    protected boolean isH4;
086    /** If the attribute should be attached to a netcdf object */
087    protected boolean isN3;
088
089    /**
090     * Constructs a NewStringAttributeDialog with specified object (dataset, group, or
091     * image) for the new attribute to be attached to.
092     *
093     * @param parent
094     *            the parent shell of the dialog
095     * @param pObject
096     *            the parent object which the new attribute is attached to.
097     * @param objs
098     *            the list of all objects.
099     */
100    public NewStringAttributeDialog(Shell parent, HObject pObject, List<HObject> objs) {
101        super(parent, pObject, objs);
102        isH4 = pObject.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4));
103        isN3 = pObject.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_NC3));
104    }
105
106    /**
107     * Open the NewStringAttributeDialog for adding a new attribute.
108     */
109    public void open() {
110        Shell parent = getParent();
111        shell = new Shell(parent, SWT.SHELL_TRIM | SWT.APPLICATION_MODAL);
112        shell.setFont(curFont);
113        shell.setText("New Attribute...");
114        shell.setImages(ViewProperties.getHdfIcons());
115        shell.setLayout(new GridLayout(1, true));
116
117
118        // Create content region
119        Composite content = new Composite(shell, SWT.NONE);
120        content.setLayout(new GridLayout(2, false));
121        content.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
122
123        Label label = new Label(content, SWT.LEFT);
124        label.setFont(curFont);
125        label.setText("Name: ");
126
127        nameField = new Text(content, SWT.SINGLE | SWT.BORDER);
128        nameField.setFont(curFont);
129        nameField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
130
131        label = new Label(content, SWT.LEFT);
132        label.setFont(curFont);
133        label.setText("Type: ");
134
135        Composite optionsComposite = new Composite(content, SWT.NONE);
136        optionsComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
137        optionsComposite.setLayout(new GridLayout(
138                (!isH5 && (parentObj instanceof Group) && ((Group) parentObj).isRoot()) ? 5 : 3,
139                        false)
140                );
141
142        // Dummy label
143        label = new Label(optionsComposite, SWT.LEFT);
144        label.setFont(curFont);
145        label.setText("");
146
147        if (!isH5 && (parentObj instanceof Group) && ((Group) parentObj).isRoot()) {
148            label = new Label(optionsComposite, SWT.LEFT);
149            label.setFont(curFont);
150            label.setText("");
151
152            label = new Label(optionsComposite, SWT.LEFT);
153            label.setFont(curFont);
154            label.setText("");
155        }
156
157        createDatatypeWidget();
158
159        if (!isH5 && (parentObj instanceof Group) && ((Group) parentObj).isRoot()) {
160            Button h4SdAttrRadioButton = new Button(optionsComposite, SWT.RADIO);
161            h4SdAttrRadioButton.setFont(curFont);
162            h4SdAttrRadioButton.setText("SD");
163            h4SdAttrRadioButton.setSelection(true);
164
165            h4GrAttrRadioButton = new Button(optionsComposite, SWT.RADIO);
166            h4GrAttrRadioButton.setFont(curFont);
167            h4GrAttrRadioButton.setText("GR");
168        }
169
170        arrayLengthLabel = new Label(content, SWT.LEFT);
171        arrayLengthLabel.setFont(curFont);
172        arrayLengthLabel.setText("Array Size: ");
173
174        lengthField = new Text(content, SWT.SINGLE | SWT.BORDER);
175        lengthField.setFont(curFont);
176        lengthField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
177        lengthField.setTextLimit(30);
178        lengthField.setText("1");
179
180        label = new Label(content, SWT.LEFT);
181        label.setFont(curFont);
182        label.setText("Value: ");
183
184        valueField = new Text(content, SWT.SINGLE | SWT.BORDER);
185        valueField.setFont(curFont);
186        valueField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
187        valueField.setText("0");
188
189        label = new Label(content, SWT.LEFT);
190        label.setFont(curFont);
191        label.setText("Object List: ");
192
193        objChoice = new Combo(content, SWT.DROP_DOWN | SWT.READ_ONLY);
194        objChoice.setFont(curFont);
195        objChoice.setEnabled(true);
196        objChoice.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
197        objChoice.addSelectionListener(new SelectionAdapter() {
198            @Override
199            public void widgetSelected(SelectionEvent e) {
200                String objName = objChoice.getItem(objChoice.getSelectionIndex());
201
202                long[] ref = null;
203                try {
204                    HObject obj = fileFormat.get(objName);
205                    ref = obj.getOID();
206                }
207                catch (Exception ex) {
208                    log.debug("object id:", ex);
209                }
210
211                if (ref != null) {
212                    if (valueField.getText().length() > 1) {
213                        valueField.setText(valueField.getText() + "," + ref);
214                        StringTokenizer st = new StringTokenizer(valueField.getText(), ",");
215                        lengthField.setText(String.valueOf(st.countTokens()));
216                    }
217                    else {
218                        valueField.setText(String.valueOf(ref));
219                        lengthField.setText("1");
220                    }
221                }
222            }
223        });
224
225        Iterator<?> it = objList.iterator();
226        HObject hobj;
227        while (it.hasNext()) {
228            hobj = (HObject) it.next();
229
230            if (hobj instanceof Group) {
231                if (((Group) hobj).isRoot()) continue;
232            }
233
234            objChoice.add(hobj.getFullName());
235        }
236
237        // Add label to take up extra space when resizing dialog
238        label = new Label(content, SWT.LEFT);
239        label.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
240
241        // Create Ok/Cancel/Help button region
242        Composite buttonComposite = new Composite(shell, SWT.NONE);
243        buttonComposite.setLayout(new GridLayout(3, false));
244        buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
245
246        Button okButton = new Button(buttonComposite, SWT.PUSH);
247        okButton.setFont(curFont);
248        okButton.setText("   &OK   ");
249        okButton.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
250        okButton.addSelectionListener(new SelectionAdapter() {
251            @Override
252            public void widgetSelected(SelectionEvent e) {
253                if (createAttribute()) {
254                    shell.dispose();
255                }
256            }
257        });
258
259        Button cancelButton = new Button(buttonComposite, SWT.PUSH);
260        cancelButton.setFont(curFont);
261        cancelButton.setText(" &Cancel ");
262        cancelButton.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, false, false));
263        cancelButton.addSelectionListener(new SelectionAdapter() {
264            @Override
265            public void widgetSelected(SelectionEvent e) {
266                newObject = null;
267                shell.dispose();
268            }
269        });
270
271        Button helpButton = new Button(buttonComposite, SWT.PUSH);
272        helpButton.setFont(curFont);
273        helpButton.setText(" &Help ");
274        helpButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, true, false));
275        helpButton.addSelectionListener(new SelectionAdapter() {
276            @Override
277            public void widgetSelected(SelectionEvent e) {
278                new HelpDialog(shell).open();
279            }
280        });
281
282        shell.pack();
283
284        shell.addDisposeListener(new DisposeListener() {
285            @Override
286            public void widgetDisposed(DisposeEvent e) {
287                if (curFont != null) curFont.dispose();
288            }
289        });
290
291        shell.setMinimumSize(shell.computeSize(SWT.DEFAULT, SWT.DEFAULT));
292
293        Rectangle parentBounds = parent.getBounds();
294        Point shellSize = shell.getSize();
295        shell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2),
296                          (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2));
297
298        shell.open();
299
300        Display display = shell.getDisplay();
301        while (!shell.isDisposed())
302            if (!display.readAndDispatch())
303                display.sleep();
304    }
305
306    @SuppressWarnings("unchecked")
307    private boolean createAttribute() {
308        Object value = null;
309        String strValue = valueField.getText();
310
311        String attrName = nameField.getText();
312        if (attrName != null) {
313            attrName = attrName.trim();
314        }
315
316        if ((attrName == null) || (attrName.length() < 1)) {
317            Tools.showError(shell, "Create", "No attribute name specified.");
318            return false;
319        }
320
321        String lengthStr = lengthField.getText();
322        log.trace("Name is {} : Length={} and Value={}", attrName, lengthStr, strValue);
323
324        int arraySize = 0;
325        if ((lengthStr == null) || (lengthStr.length() <= 0)) {
326            arraySize = 1;
327        }
328        else {
329            try {
330                arraySize = Integer.parseInt(lengthStr);
331            }
332            catch (Exception e) {
333                arraySize = -1;
334            }
335        }
336
337        if (arraySize <= 0) {
338            Tools.showError(shell, "Create", "Invalid attribute length.");
339            return false;
340        }
341
342        StringTokenizer st = new StringTokenizer(strValue, ",");
343        int count = Math.min(arraySize, st.countTokens());
344        String theToken;
345        log.trace("Count of Values is {}", count);
346
347        // set datatype class
348        Datatype datatype = super.createNewDatatype(null);
349        if (isVLen) {
350            log.trace("Attribute isVLen={} and tsize={}", isVLen, tsize);
351            String[] strArray = { strValue };
352            value = strArray;
353        }
354        else {
355            if (tclass == Datatype.CLASS_STRING) {
356                if (!isVlenStr) {
357                    if (strValue.length() > tsize) {
358                        strValue = strValue.substring(0, tsize);
359                    }
360                }
361
362                String[] strArray = { strValue };
363                value = strArray;
364
365                if (isH5) {
366                    arraySize = 1; // support string type
367                }
368                else {
369                    arraySize = tsize; // array of characters
370                }
371                log.trace("Attribute CLASS_STRING: isVlenStr={} and tsize={} and arraySize={}", isVlenStr, tsize, arraySize);
372            }
373            else if (tclass == Datatype.CLASS_REFERENCE) {
374                arraySize = st.countTokens();
375                long[] ref = new long[arraySize];
376                for (int j = 0; j < arraySize; j++) {
377                    theToken = st.nextToken().trim();
378                    try {
379                        ref[j] = Long.parseLong(theToken);
380                    }
381                    catch (NumberFormatException ex) {
382                        Tools.showError(shell, "Create", ex.getMessage());
383                        return false;
384                    }
385                }
386
387                value = ref;
388                log.trace("Attribute CLASS_REFERENCE: tsize={} and arraySize={}", tsize, arraySize);
389            }
390            else if (tclass == Datatype.CLASS_INTEGER) {
391                if (tsign == Datatype.SIGN_NONE) {
392                    if (tsize == 1) {
393                        byte[] b = new byte[arraySize];
394                        short sv = 0;
395                        for (int j = 0; j < count; j++) {
396                            theToken = st.nextToken().trim();
397                            try {
398                                sv = Short.parseShort(theToken);
399                            }
400                            catch (NumberFormatException ex) {
401                                Tools.showError(shell, "Create", ex.getMessage());
402                                return false;
403                            }
404                            if (sv < 0) {
405                                sv = 0;
406                            }
407                            else if (sv > 255) {
408                                sv = 255;
409                            }
410                            b[j] = (byte) sv;
411                        }
412                        value = b;
413                    }
414                    else if (tsize == 2) {
415                        short[] s = new short[arraySize];
416                        int iv = 0;
417                        for (int j = 0; j < count; j++) {
418                            theToken = st.nextToken().trim();
419                            try {
420                                iv = Integer.parseInt(theToken);
421                            }
422                            catch (NumberFormatException ex) {
423                                Tools.showError(shell, "Create", ex.getMessage());
424                                return false;
425                            }
426                            if (iv < 0) {
427                                iv = 0;
428                            }
429                            else if (iv > 65535) {
430                                iv = 65535;
431                            }
432                            s[j] = (short) iv;
433                        }
434                        value = s;
435                    }
436                    else if ((tsize == 4) || (tsize == -1)) {
437                        int[] i = new int[arraySize];
438                        long lv = 0;
439                        for (int j = 0; j < count; j++) {
440                            theToken = st.nextToken().trim();
441                            try {
442                                lv = Long.parseLong(theToken);
443                            }
444                            catch (NumberFormatException ex) {
445                                Tools.showError(shell, "Create", ex.getMessage());
446                                return false;
447                            }
448                            if (lv < 0) {
449                                lv = 0;
450                            }
451                            if (lv > 4294967295L) {
452                                lv = 4294967295L;
453                            }
454                            i[j] = (int) lv;
455                        }
456                        value = i;
457                    }
458                    else if (tsize == 8) {
459                        long[] i = new long[arraySize];
460                        BigInteger lv = BigInteger.valueOf(0);
461                        for (int j = 0; j < count; j++) {
462                            theToken = st.nextToken().trim();
463                            try {
464                                lv = new BigInteger(theToken);
465                            }
466                            catch (NumberFormatException ex) {
467                                Tools.showError(shell, "Create", ex.getMessage());
468                                return false;
469                            }
470                            i[j] = lv.longValue();
471                        }
472                        value = i;
473                    }
474                }
475                else {
476                    if (tsize == 1) {
477                        byte[] b = new byte[arraySize];
478                        for (int j = 0; j < count; j++) {
479                            theToken = st.nextToken().trim();
480                            try {
481                                b[j] = Byte.parseByte(theToken);
482                            }
483                            catch (NumberFormatException ex) {
484                                Tools.showError(shell, "Create", ex.getMessage());
485                                return false;
486                            }
487                        }
488                        value = b;
489                    }
490                    else if (tsize == 2) {
491                        short[] s = new short[arraySize];
492
493                        for (int j = 0; j < count; j++) {
494                            theToken = st.nextToken().trim();
495                            try {
496                                s[j] = Short.parseShort(theToken);
497                            }
498                            catch (NumberFormatException ex) {
499                                Tools.showError(shell, "Create", ex.getMessage());
500                                return false;
501                            }
502                        }
503                        value = s;
504                    }
505                    else if ((tsize == 4) || (tsize == -1)) {
506                        int[] i = new int[arraySize];
507
508                        for (int j = 0; j < count; j++) {
509                            theToken = st.nextToken().trim();
510                            try {
511                                i[j] = Integer.parseInt(theToken);
512                            }
513                            catch (NumberFormatException ex) {
514                                Tools.showError(shell, "Create", ex.getMessage());
515                                return false;
516                            }
517                        }
518                        value = i;
519                    }
520                    else if (tsize == 8) {
521                        long[] l = new long[arraySize];
522                        for (int j = 0; j < count; j++) {
523                            theToken = st.nextToken().trim();
524                            try {
525                                l[j] = Long.parseLong(theToken);
526                            }
527                            catch (NumberFormatException ex) {
528                                Tools.showError(shell, "Create", ex.getMessage());
529                                return false;
530                            }
531                        }
532                        value = l;
533                    }
534                }
535            }
536
537            if (tclass == Datatype.CLASS_FLOAT) {
538                if ((tsize == 4) || (tsize == -1)) {
539                    float[] f = new float[arraySize];
540                    for (int j = 0; j < count; j++) {
541                        theToken = st.nextToken().trim();
542                        try {
543                            f[j] = Float.parseFloat(theToken);
544                        }
545                        catch (NumberFormatException ex) {
546                            Tools.showError(shell, "Create", ex.getMessage());
547                            return false;
548                        }
549                        if (Float.isInfinite(f[j]) || Float.isNaN(f[j])) {
550                            f[j] = 0;
551                        }
552                    }
553                    value = f;
554                }
555                else if (tsize == 8) {
556                    double[] d = new double[arraySize];
557                    for (int j = 0; j < count; j++) {
558                        theToken = st.nextToken().trim();
559                        try {
560                            d[j] = Double.parseDouble(theToken);
561                        }
562                        catch (NumberFormatException ex) {
563                            Tools.showError(shell, "Create", ex.getMessage());
564                            return false;
565                        }
566                        if (Double.isInfinite(d[j]) || Double.isNaN(d[j])) {
567                            d[j] = 0;
568                        }
569                    }
570                    value = d;
571                }
572            }
573        }
574
575        long[] dims = { arraySize };
576        Attribute attr = null;
577        try {
578            if (isH4)
579                attr = new hdf.object.h4.H4ScalarAttribute(parentObj, attrName, datatype, dims);
580            else
581                attr = new hdf.object.nc2.NC2Attribute(parentObj, attrName, datatype, dims);
582        }
583        catch (Exception ex) {
584            Tools.showError(shell, "Create", ex.getMessage());
585            log.debug("createAttribute(): ", ex);
586            return false;
587        }
588        if (attr ==null) {
589            Tools.showError(shell, "Create", "Attribute could not be created");
590            log.debug("createAttribute(): failed");
591            return false;
592        }
593        attr.setAttributeData(value);
594
595        try {
596            if (!isH5 && (parentObj instanceof Group) && ((Group) parentObj).isRoot() && h4GrAttrRadioButton.getSelection()) {
597                parentObj.getFileFormat().writeAttribute(parentObj, attr, false);
598                // don't find a good way to write HDF4 global
599                // attribute. Use the isExisted to separate the
600                // global attribute is GR or SD
601
602                if (((MetaDataContainer) parentObj).getMetadata() == null) {
603                    ((MetaDataContainer) parentObj).getMetadata().add(attr);
604                }
605            }
606            else {
607                log.trace("writeMetadata() via write()");
608                attr.writeAttribute();
609            }
610        }
611        catch (Exception ex) {
612            Tools.showError(shell, "Create", ex.getMessage());
613            log.debug("createAttribute(): ", ex);
614            return false;
615        }
616
617        newObject = (HObject)attr;
618
619        return true;
620    }
621
622    private class HelpDialog extends Dialog {
623        private Shell helpShell;
624
625        public HelpDialog(Shell parent) {
626            super(parent, SWT.APPLICATION_MODAL);
627        }
628
629        public void open() {
630            Shell parent = getParent();
631            helpShell = new Shell(parent, SWT.TITLE | SWT.CLOSE |
632                    SWT.RESIZE | SWT.BORDER | SWT.APPLICATION_MODAL);
633            helpShell.setFont(curFont);
634            helpShell.setText("Create New Attribute");
635            helpShell.setImages(ViewProperties.getHdfIcons());
636            helpShell.setLayout(new GridLayout(1, true));
637
638            // Try to create a Browser on platforms that support it
639            try {
640                Browser browser = new Browser(helpShell, SWT.NONE);
641                browser.setFont(curFont);
642                browser.setBounds(0, 0, 500, 500);
643                browser.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
644
645                if (ClassLoader.getSystemResource("hdf/view/HDFView.class").toString().startsWith("jar")) {
646                    // Attempt to load HTML help file from jar
647                    try (InputStream in = getClass().getClassLoader().getResourceAsStream("hdf/view/NewAttrHelp.html")) {
648                        Scanner scan = new Scanner(in);
649                        StringBuilder buffer = new StringBuilder();
650                        while(scan.hasNextLine()) {
651                            buffer.append(scan.nextLine());
652                        }
653
654                        browser.setText(buffer.toString());
655
656                        scan.close();
657                    }
658                    catch (Exception e) {
659                        StringBuilder buff = new StringBuilder();
660                        buff.append("<html>")
661                            .append("<body>")
662                            .append("ERROR: cannot load help information.")
663                            .append("</body>")
664                            .append("</html>");
665                        browser.setText(buff.toString(), true);
666                    }
667                }
668                else {
669                    try {
670                        URL url = null, url2 = null, url3 = null;
671                        String rootPath = ViewProperties.getViewRoot();
672
673                        try {
674                            url = new URL("file://" + rootPath + "/HDFView.jar");
675                        }
676                        catch (java.net.MalformedURLException mfu) {
677                            log.debug("help information:", mfu);
678                        }
679
680                        try {
681                            url2 = new URL("file://" + rootPath + "/");
682                        }
683                        catch (java.net.MalformedURLException mfu) {
684                            log.debug("help information:", mfu);
685                        }
686
687                        try {
688                            url3 = new URL("file://" + rootPath + "/src/");
689                        }
690                        catch (java.net.MalformedURLException mfu) {
691                            log.debug("help information:", mfu);
692                        }
693
694                        URL uu[] = { url, url2, url3 };
695                        try (URLClassLoader cl = new URLClassLoader(uu)) {
696                            URL u = cl.findResource("hdf/view/NewAttrHelp.html");
697
698                            browser.setUrl(u.toString());
699                        }
700                        catch (Exception ex) {
701                            log.trace("URLClassLoader failed:", ex);
702                        }
703                    }
704                    catch (Exception e) {
705                        StringBuilder buff = new StringBuilder();
706                        buff.append("<html>")
707                            .append("<body>")
708                            .append("ERROR: cannot load help information.")
709                            .append("</body>")
710                            .append("</html>");
711                        browser.setText(buff.toString(), true);
712                    }
713                }
714
715                Button okButton = new Button(helpShell, SWT.PUSH);
716                okButton.setFont(curFont);
717                okButton.setText("   &OK   ");
718                okButton.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, true, false));
719                okButton.addSelectionListener(new SelectionAdapter() {
720                    @Override
721                    public void widgetSelected(SelectionEvent e) {
722                        helpShell.dispose();
723                    }
724                });
725
726                helpShell.pack();
727
728                helpShell.setSize(new Point(500, 500));
729
730                Rectangle parentBounds = parent.getBounds();
731                Point shellSize = helpShell.getSize();
732                helpShell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2),
733                                      (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2));
734
735                helpShell.open();
736
737                Display display = parent.getDisplay();
738                while(!helpShell.isDisposed()) {
739                    if (!display.readAndDispatch())
740                        display.sleep();
741                }
742            }
743            catch (Error er) {
744                // Try opening help link in external browser if platform
745                // doesn't support SWT browser
746                Tools.showError(shell, "Browser support",
747                        "Platform doesn't support Browser. Opening external link in web browser...");
748
749                //TODO: Add support for launching in external browser
750            }
751            catch (Exception ex) {
752                log.debug("Open New Attribute Help failure: ", ex);
753            }
754        }
755    }
756
757    /** @return the new attribute created. */
758    public Attribute getAttribute() {
759        return (Attribute)newObject;
760    }
761}