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