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