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