    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.util.Iterator;
    018import java.util.List;
    019import java.util.Vector;
    020
    021import org.slf4j.Logger;
    022import org.slf4j.LoggerFactory;
    023
    024import org.eclipse.swt.SWT;
    025import org.eclipse.swt.events.SelectionAdapter;
    026import org.eclipse.swt.events.SelectionEvent;
    027import org.eclipse.swt.graphics.Font;
    028import org.eclipse.swt.layout.GridData;
    029import org.eclipse.swt.layout.GridLayout;
    030import org.eclipse.swt.widgets.Button;
    031import org.eclipse.swt.widgets.Combo;
    032import org.eclipse.swt.widgets.Dialog;
    033import org.eclipse.swt.widgets.Display;
    034import org.eclipse.swt.widgets.Label;
    035import org.eclipse.swt.widgets.Shell;
    036import org.eclipse.swt.widgets.Text;
    037
    038import hdf.object.Datatype;
    039import hdf.object.FileFormat;
    040import hdf.object.Group;
    041import hdf.object.HObject;
    042import hdf.object.h5.H5Datatype;
    043import hdf.view.Tools;
    044import hdf.view.ViewProperties;
    045
    046/**
    047 * NewDataDialog is an intermediate class for creating data types.
    048 */
    049public class NewDataObjectDialog extends Dialog {
    050
    051    private static final Logger log = LoggerFactory.getLogger(NewDataObjectDialog.class);
    052
    053    /** the visual shell for the dialog */
    054    protected Shell   shell;
    055
    056    /** the current font */
    057    protected Font    curFont;
    058
    059    /** the object which the this object is attached */
    060    protected HObject parentObj;
    061
    062    /** the object referenced */
    063    protected HObject refObject;
    064
    065    /** the object created */
    066    protected HObject newObject;
    067
    068    /** TextField for entering the length of the data array or string. */
    069    protected Text    lengthField;
    070
    071    /** The Choice of the datatypes */
    072    /** The named datatype combobox for the object */
    073    protected Combo   namedChoice;
    074    /** The class combobox for the object */
    075    protected Combo   classChoice;
    076    /** The size combobox for the object */
    077    protected Combo   sizeChoice;
    078    /** The endianess combobox for the object */
    079    protected Combo   endianChoice;
    080
    081    /** The Choice of the object list */
    082    /** The committed datatype button for the object */
    083    protected Button  useCommittedType;
    084    /** The unsigned data button for the object */
    085    protected Button  checkUnsigned;
    086    /** The list of objects for the object */
    087    protected List<?> objList;
    088    /** The list of datatypes for the object */
    089    protected List<Datatype> namedList;
    090    /** The length label for the object */
    091    protected Label   arrayLengthLabel;
    092
    093    /** The attributes of the datatype */
    094    /** The default class for the object */
    095    public int tclass = Datatype.CLASS_NO_CLASS;
    096    /** The default size for the object */
    097    public int tsize = Datatype.NATIVE;
    098    /** The default  byte order for the object */
    099    public int torder = Datatype.NATIVE;
    100    /** The default sign for the object */
    101    public int tsign = Datatype.NATIVE;
    102    /** If the object is an enum object */
    103    public boolean isEnum = false;
    104    /** The enum mapping for the object */
    105    public String strEnumMap = null;
    106    /** If the object is a variable length data object */
    107    public boolean isVLen = false;
    108    /** If the object is a variable length string */
    109    public boolean isVlenStr = false;
    110
    111    /** The file format associated with this object */
    112    protected FileFormat fileFormat;
    113
    114    /** If the object should be attached to a hdf5 object */
    115    protected boolean isH5;
    116
    117    /**
    118     * The NewDataObjectDialog constructor.
    119     *
    120     * @param parent
    121     *        the dialog parent shell
    122     * @param pGroup
    123     *        the dialog parent group object
    124     * @param objs
    125     *        the list of objects
    126     */
    127    public NewDataObjectDialog(Shell parent, HObject pGroup, List<?> objs) {
    128        super(parent, SWT.APPLICATION_MODAL);
    129
    130        try {
    131            curFont = new Font(
    132                    Display.getCurrent(),
    133                    ViewProperties.getFontType(),
    134                    ViewProperties.getFontSize(),
    135                    SWT.NORMAL);
    136        }
    137        catch (Exception ex) {
    138            curFont = null;
    139        }
    140
    141        newObject = null;
    142        parentObj = pGroup;
    143        objList = objs;
    144
    145        fileFormat = pGroup.getFileFormat();
    146        isH5 = pGroup.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5));
    147    }
    148
    149    /** the new dataset properties to be created. */
    150    public void createDatatypeWidget() {
    151        Label label;
    152
    153        // Create Datatype region
    154        org.eclipse.swt.widgets.Group datatypeGroup = new org.eclipse.swt.widgets.Group(shell, SWT.NONE);
    155        datatypeGroup.setFont(curFont);
    156        datatypeGroup.setText("Datatype");
    157        datatypeGroup.setLayout(new GridLayout(4, true));
    158        datatypeGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
    159
    160        useCommittedType = new Button(datatypeGroup, SWT.CHECK);
    161        useCommittedType.setFont(curFont);
    162        useCommittedType.setText("Use Committed Datatype");
    163        useCommittedType.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
    164        useCommittedType.setEnabled(isH5);
    165
    166        if(isH5) {
    167            label = new Label(datatypeGroup, SWT.LEFT);
    168            label.setFont(curFont);
    169            label.setText("Committed Datatype: ");
    170
    171            namedChoice = new Combo(datatypeGroup, SWT.DROP_DOWN | SWT.BORDER | SWT.READ_ONLY);
    172            namedChoice.setFont(curFont);
    173            namedChoice.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
    174            namedChoice.addSelectionListener(new SelectionAdapter() {
    175                @Override
    176                public void widgetSelected(SelectionEvent e) {
    177                    refObject = namedList.get(namedChoice.getSelectionIndex());
    178                }
    179            });
    180
    181            //Dummy label
    182            label = new Label(datatypeGroup, SWT.LEFT);
    183            label.setFont(curFont);
    184            label.setText("");
    185
    186            namedList = new Vector<>(objList.size());
    187            Object obj = null;
    188            Iterator<?> iterator = objList.iterator();
    189            while (iterator.hasNext()) {
    190                obj = iterator.next();
    191                if (obj instanceof Datatype) {
    192                    H5Datatype ndt = (H5Datatype) obj;
    193                    namedList.add(ndt);
    194                    namedChoice.add(((Datatype)obj).getFullName());
    195                }
    196            }
    197
    198            if (refObject != null)
    199                namedChoice.select(namedChoice.indexOf(((Datatype)refObject).getFullName()));
    200        }
    201
    202        label = new Label(datatypeGroup, SWT.LEFT);
    203        label.setFont(curFont);
    204        label.setText("Datatype Class");
    205
    206        label = new Label(datatypeGroup, SWT.LEFT);
    207        label.setFont(curFont);
    208        label.setText("Size (bits)");
    209
    210        label = new Label(datatypeGroup, SWT.LEFT);
    211        label.setFont(curFont);
    212        label.setText("Byte Ordering");
    213
    214        checkUnsigned = new Button(datatypeGroup, SWT.CHECK);
    215        checkUnsigned.setFont(curFont);
    216        checkUnsigned.setText("Unsigned");
    217        checkUnsigned.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
    218
    219        classChoice = new Combo(datatypeGroup, SWT.DROP_DOWN | SWT.READ_ONLY);
    220        classChoice.setFont(curFont);
    221        classChoice.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
    222        classChoice.addSelectionListener(new SelectionAdapter() {
    223            @Override
    224            public void widgetSelected(SelectionEvent e) {
    225                int idx = classChoice.getSelectionIndex();
    226                sizeChoice.select(0);
    227                endianChoice.select(0);
    228                lengthField.setEnabled(false);
    229
    230                if ((idx == 0) || (idx == 6)) { // INTEGER
    231                    sizeChoice.setEnabled(true);
    232                    endianChoice.setEnabled(isH5);
    233                    checkUnsigned.setEnabled(true);
    234
    235                    if (sizeChoice.getItemCount() == 3) {
    236                        sizeChoice.remove("32");
    237                        sizeChoice.remove("64");
    238                        sizeChoice.add("8");
    239                        sizeChoice.add("16");
    240                        sizeChoice.add("32");
    241                        sizeChoice.add("64");
    242                    }
    243                }
    244                else if ((idx == 1) || (idx == 7)) { // FLOAT
    245                    sizeChoice.setEnabled(true);
    246                    endianChoice.setEnabled(isH5);
    247                    checkUnsigned.setEnabled(false);
    248
    249                    if (sizeChoice.getItemCount() == 5) {
    250                        sizeChoice.remove("16");
    251                        sizeChoice.remove("8");
    252                    }
    253                }
    254                else if (idx == 2) { // CHAR
    255                    sizeChoice.setEnabled(false);
    256                    endianChoice.setEnabled(isH5);
    257                    checkUnsigned.setEnabled(true);
    258                }
    259                else if (idx == 3) { // STRING
    260                    sizeChoice.setEnabled(false);
    261                    endianChoice.setEnabled(false);
    262                    checkUnsigned.setEnabled(false);
    263                    lengthField.setEnabled(true);
    264                    lengthField.setText("String length");
    265                }
    266                else if (idx == 4) { // REFERENCE
    267                    sizeChoice.setEnabled(false);
    268                    endianChoice.setEnabled(false);
    269                    checkUnsigned.setEnabled(false);
    270                    lengthField.setEnabled(false);
    271                }
    272                else if (idx == 5) { // ENUM
    273                    sizeChoice.setEnabled(true);
    274                    checkUnsigned.setEnabled(true);
    275                    lengthField.setEnabled(true);
    276                    lengthField.setText("0=R,1=G,#=TXT,...");
    277                }
    278                else if (idx == 8) {
    279                    sizeChoice.setEnabled(false);
    280                    endianChoice.setEnabled(false);
    281                    checkUnsigned.setEnabled(false);
    282                    lengthField.setEnabled(false);
    283                }
    284            }
    285        });
    286
    287        classChoice.add("INTEGER");
    288        classChoice.add("FLOAT");
    289        classChoice.add("CHAR");
    290
    291        if(isH5) {
    292            classChoice.add("STRING");
    293            classChoice.add("REFERENCE");
    294            classChoice.add("ENUM");
    295            classChoice.add("VLEN_INTEGER");
    296            classChoice.add("VLEN_FLOAT");
    297            classChoice.add("VLEN_STRING");
    298        }
    299
    300        sizeChoice = new Combo(datatypeGroup, SWT.DROP_DOWN | SWT.READ_ONLY);
    301        sizeChoice.setFont(curFont);
    302        sizeChoice.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
    303        sizeChoice.addSelectionListener(new SelectionAdapter() {
    304            @Override
    305            public void widgetSelected(SelectionEvent e) {
    306                if (classChoice.getSelectionIndex() == 0) {
    307                    checkUnsigned.setEnabled(true);
    308                }
    309            }
    310        });
    311
    312        if(isH5) {
    313            sizeChoice.add("NATIVE");
    314        }
    315        else {
    316            sizeChoice.add("DEFAULT");
    317        }
    318
    319        sizeChoice.add("8");
    320        sizeChoice.add("16");
    321        sizeChoice.add("32");
    322        sizeChoice.add("64");
    323
    324        endianChoice = new Combo(datatypeGroup, SWT.DROP_DOWN | SWT.READ_ONLY);
    325        endianChoice.setFont(curFont);
    326        endianChoice.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
    327        endianChoice.setEnabled(isH5);
    328
    329        if(isH5) {
    330            endianChoice.add("NATIVE");
    331            endianChoice.add("LITTLE ENDIAN");
    332            endianChoice.add("BIG ENDIAN");
    333        }
    334        else {
    335            endianChoice.add("DEFAULT");
    336        }
    337
    338        lengthField = new Text(datatypeGroup, SWT.SINGLE | SWT.BORDER);
    339        lengthField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
    340        lengthField.setFont(curFont);
    341        lengthField.setText("String Length");
    342        lengthField.setEnabled(false);
    343
    344        classChoice.select(0);
    345        sizeChoice.select(0);
    346        endianChoice.select(0);
    347
    348        refObject = null;
    349        classChoice.setEnabled(true);
    350        sizeChoice.setEnabled(true);
    351        endianChoice.setEnabled(isH5);
    352        checkUnsigned.setEnabled(true);
    353    }
    354
    355    /**
    356     * Create the datatype according to the settings.
    357     *
    358     * @param name
    359     *        the datatype name
    360     *
    361     * @return the new object created.
    362     */
    363    public Datatype createNewDatatype(String name) {
    364        Datatype datatype = null;
    365
    366        tclass = Datatype.CLASS_NO_CLASS;
    367        tsize = Datatype.NATIVE;
    368        torder = Datatype.NATIVE;
    369        tsign = Datatype.NATIVE;
    370        isEnum = false;
    371        strEnumMap = null;
    372        isVLen = false;
    373        isVlenStr = false;
    374
    375        if (useCommittedType.getSelection()) {
    376            datatype = (Datatype)refObject;
    377        }
    378        else {
    379           // idx is set to datatype class
    380            int idx = classChoice.getSelectionIndex();
    381            if (idx == 0) {
    382                tclass = Datatype.CLASS_INTEGER;
    383                if (checkUnsigned.getSelection()) {
    384                    tsign = Datatype.SIGN_NONE;
    385                }
    386            }
    387            else if (idx == 1) {
    388                tclass = Datatype.CLASS_FLOAT;
    389            }
    390            else if (idx == 2) {
    391                tclass = Datatype.CLASS_CHAR;
    392                if (checkUnsigned.getSelection()) {
    393                    tsign = Datatype.SIGN_NONE;
    394                }
    395            }
    396            else if (idx == 3) {
    397                tclass = Datatype.CLASS_STRING;
    398            }
    399            else if (idx == 4) {
    400                tclass = Datatype.CLASS_REFERENCE;
    401            }
    402            else if (idx == 5) {
    403                isEnum = true;
    404                tclass = Datatype.CLASS_ENUM;
    405            }
    406            else if (idx == 6) {
    407                isVLen = true;
    408                tclass = Datatype.CLASS_INTEGER;
    409                if (checkUnsigned.getSelection()) {
    410                    tsign = Datatype.SIGN_NONE;
    411                }
    412            }
    413            else if (idx == 7) {
    414                isVLen = true;
    415                tclass = Datatype.CLASS_FLOAT;
    416            }
    417            else if (idx == 8) {
    418                tclass = Datatype.CLASS_STRING;
    419                isVlenStr = true;
    420                tsize = -1;
    421            }
    422
    423            // idx is set to datatype size
    424            idx = sizeChoice.getSelectionIndex();
    425            if (tclass == Datatype.CLASS_STRING) {
    426                if (!isVlenStr) {
    427                    int stringLength = 0;
    428                    try {
    429                        stringLength = Integer.parseInt(lengthField.getText());
    430                    }
    431                    catch (NumberFormatException ex) {
    432                        stringLength = -1;
    433                    }
    434
    435                    if (stringLength <= 0) {
    436                        shell.getDisplay().beep();
    437                        Tools.showError(shell, "Create", "Invalid string length: " + lengthField.getText());
    438                        return null;
    439                    }
    440                    tsize = stringLength;
    441                }
    442            }
    443            else if (tclass == Datatype.CLASS_REFERENCE) {
    444                tsize = 1;
    445                torder = Datatype.NATIVE;
    446            }
    447            else if (idx == 0) {
    448                tsize = Datatype.NATIVE;
    449            }
    450            else if (tclass == Datatype.CLASS_FLOAT) {
    451                tsize = idx * 4;
    452            }
    453            else if (tclass == Datatype.CLASS_INTEGER || tclass == Datatype.CLASS_ENUM) {
    454                // Note that idx == 0 is set to either
    455                //       "NATIVE" if isH5 is true
    456                //       "DEFAULT" otherwise
    457                switch(idx) {
    458                    case 1:
    459                        tsize = 1;
    460                        break;
    461                    case 2:
    462                        tsize = 2;
    463                        break;
    464                    case 3:
    465                        tsize = 4;
    466                        break;
    467                    case 4:
    468                        tsize = 8;
    469                        break;
    470                    default:
    471                        tsize = -1;
    472                        break;
    473                }
    474                log.trace("CLASS_INTEGER or CLASS_ENUM: tsize={}", tsize);
    475            }
    476            else if (tclass == Datatype.CLASS_FLOAT) {
    477                tsize = (idx + 1) * 4;
    478                log.trace("CLASS_FLOAT: tsize={}", tsize);
    479            }
    480            else {
    481                tsize = 1 << (idx - 1);
    482            }
    483
    484            if ((tsize == 8) && !isH5 && (tclass == Datatype.CLASS_INTEGER)) {
    485                shell.getDisplay().beep();
    486                Tools.showError(shell, "Create", "HDF4 does not support 64-bit integer.");
    487                return null;
    488            }
    489
    490            // set order
    491            idx = endianChoice.getSelectionIndex();
    492            if (idx == 0) {
    493                torder = Datatype.NATIVE;
    494            }
    495            else if (idx == 1) {
    496                torder = Datatype.ORDER_LE;
    497            }
    498            else {
    499                torder = Datatype.ORDER_BE;
    500            }
    501
    502            Datatype thedatatype = null;
    503            try {
    504                Datatype basedatatype = null;
    505                if (isVLen) {
    506                    basedatatype = fileFormat.createDatatype(tclass, tsize, torder, tsign);
    507                    tclass = Datatype.CLASS_VLEN;
    508                    thedatatype = fileFormat.createDatatype(tclass, tsize, torder, tsign, basedatatype);
    509                }
    510                else if (isEnum && isH5) {
    511                    strEnumMap = lengthField.getText();
    512                    if ((strEnumMap == null) || (strEnumMap.length() < 1) || strEnumMap.endsWith("...")) {
    513                        shell.getDisplay().beep();
    514                        Tools.showError(shell, "Create", "Invalid member values: " + lengthField.getText());
    515                        return null;
    516                    }
    517                    log.trace("CLASS_ENUM enumStr={}", strEnumMap);
    518
    519                    thedatatype = fileFormat.createDatatype(tclass, tsize, torder, tsign);
    520                    thedatatype.setEnumMembers(strEnumMap);
    521                }
    522                else
    523                    thedatatype = fileFormat.createDatatype(tclass, tsize, torder, tsign);
    524
    525                if(isH5)
    526                    datatype = fileFormat.createNamedDatatype(thedatatype, name);
    527                else
    528                    datatype = thedatatype;
    529            }
    530            catch (Exception ex) {
    531                shell.getDisplay().beep();
    532                Tools.showError(shell, "Create", ex.getMessage());
    533                return null;
    534            }
    535        }
    536        return datatype;
    537    }
    538
    539    /** @return the new object created. */
    540    public HObject getObject() {
    541        return newObject;
    542    }
    543
    544    /** @return the parent group of the new dataset. */
    545    public Group getParentGroup() {
    546        return (Group) parentObj;
    547    }
    548}