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