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