    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.lang.reflect.Array;
    018
    019import org.eclipse.swt.SWT;
    020import org.eclipse.swt.events.DisposeEvent;
    021import org.eclipse.swt.events.DisposeListener;
    022import org.eclipse.swt.events.SelectionAdapter;
    023import org.eclipse.swt.events.SelectionEvent;
    024import org.eclipse.swt.graphics.Font;
    025import org.eclipse.swt.graphics.Point;
    026import org.eclipse.swt.graphics.Rectangle;
    027import org.eclipse.swt.layout.GridData;
    028import org.eclipse.swt.layout.GridLayout;
    029import org.eclipse.swt.widgets.Button;
    030import org.eclipse.swt.widgets.Composite;
    031import org.eclipse.swt.widgets.Dialog;
    032import org.eclipse.swt.widgets.Display;
    033import org.eclipse.swt.widgets.Label;
    034import org.eclipse.swt.widgets.List;
    035import org.eclipse.swt.widgets.Shell;
    036import org.eclipse.swt.widgets.Text;
    037
    038import hdf.view.Tools;
    039import hdf.view.ViewProperties;
    040
    041/**
    042 * MathConversionDialog shows a message dialog requesting user input for math
    043 * conversion.
    044 *
    045 * @author Jordan T. Henderson
    046 * @version 2.4 1/28/2016
    047 */
    048public class MathConversionDialog extends Dialog {
    049    private Shell       shell;
    050
    051    private Font        curFont;
    052
    053    private Text        aField;
    054
    055    private Text        bField;
    056
    057    private Text        infoArea;
    058
    059    private List        functionList;
    060
    061    private Object      dataValue;
    062
    063    private char        NT;
    064
    065    private String[]    functionDescription;
    066
    067    private boolean     isConverted;
    068
    069    /**
    070     * Constructs MathConversionDialog.
    071     *
    072     * @param parent
    073     *            the owner of the input
    074     * @param data
    075     *            the data array to convert.
    076     */
    077    public MathConversionDialog(Shell parent, Object data) {
    078        super(parent, SWT.APPLICATION_MODAL);
    079
    080        try {
    081            curFont = new Font(
    082                    Display.getCurrent(),
    083                    ViewProperties.getFontType(),
    084                    ViewProperties.getFontSize(),
    085                    SWT.NORMAL);
    086        }
    087        catch (Exception ex) {
    088            curFont = null;
    089        }
    090
    091        isConverted = false;
    092        dataValue = data;
    093        NT = ' ';
    094
    095        String cName = data.getClass().getName();
    096        int cIndex = cName.lastIndexOf('[');
    097        if (cIndex >= 0) {
    098            NT = cName.charAt(cIndex + 1);
    099        }
    100
    101        String[] tmpStrs = {
    102                "The filter by lower and upper bounds. x=a if x<a; x=b if x>b."
    103                        + "\ne.g.\n x=5, [0, 127]=5\n x=-5, [0, 127]=0\n x=255, [0, 127]=127.",
    104                "The absolute value of a number, the number without its sign."
    105                        + "\ne.g.\n abs(5)=5\n abs(-5)=5.",
    106                "Linear function." + "\ne.g.\n a=5, b=2, x=2.5, a+b*x=10.",
    107                "The result of a number raised to power of a."
    108                        + "\ne.g.\n x=2.5, a=10, pow(x, a)=9536.743\n x=25, a=0.5, pow(x, a)=5.",
    109                "The exponential number e (i.e., 2.718...) raised to the power of x."
    110                        + "\ne.g.\n exp(5.0)=148.41316\n exp(5.5)=244.69193",
    111                "The natural logarithm (base e) of x."
    112                        + "\ne.g.\n ln(20.085541)=3\n ln(10)=2.302585",
    113                "The logarithm of x to the base of a, \"a\" must be an integer > 0."
    114                        + "\ne.g.\n log(10, 2)=3.321928\n log(2, 10)=0.30103",
    115                "The trigonometric sine of angle x in radians."
    116                        + "\ne.g.\n sin(0.523599)=0.5\n sin(1.047198)=0.866025",
    117                "The trigonometric cosine of angle x in radians."
    118                        + "\ne.g.\n cos(0.523599)=0.866025\n cos(1.047198)=0.5",
    119                "The trigonometric tangent of angle x in radians."
    120                        + "\ne.g.\n tan(0.785398)=1\n tan(1.047198)=1.732051" };
    121
    122        functionDescription = tmpStrs;
    123    }
    124
    125    /**
    126     * Open the MathConversionDialog for converting data.
    127     */
    128    public void open() {
    129        Shell parent = getParent();
    130        shell = new Shell(parent, SWT.SHELL_TRIM | SWT.APPLICATION_MODAL);
    131        shell.setFont(curFont);
    132        shell.setText("Convert Data...");
    133        shell.setImages(ViewProperties.getHdfIcons());
    134        shell.setLayout(new GridLayout(1, true));
    135
    136        // Create content region
    137        org.eclipse.swt.widgets.Group contentGroup = new org.eclipse.swt.widgets.Group(shell, SWT.NONE);
    138        contentGroup.setFont(curFont);
    139        contentGroup.setText("Converting Data With A Mathematic Function");
    140        contentGroup.setLayout(new GridLayout(2, false));
    141        contentGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
    142
    143        String[] functionNames = { "[a, b]", "abs (x)", "a + b * x",
    144                "pow (x, a)", "exp (x)", "ln (x)", "log (a, x)", "sin (x)",
    145                "cos (x)", "tan (x)" };
    146
    147        functionList = new List(contentGroup, SWT.SINGLE | SWT.BORDER);
    148        functionList.setFont(curFont);
    149        functionList.setItems(functionNames);
    150        GridData functionListData = new GridData(SWT.FILL, SWT.FILL, true, false);
    151        functionListData.minimumWidth = 350;
    152        functionList.setLayoutData(functionListData);
    153        functionList.addSelectionListener(new SelectionAdapter() {
    154            @Override
    155            public void widgetSelected(SelectionEvent e) {
    156                int index = functionList.getSelectionIndex();
    157                infoArea.setText(functionDescription[index]);
    158
    159                if ((index == 0) || (index == 2)) {
    160                    aField.setEnabled(true);
    161                    bField.setEnabled(true);
    162                }
    163                else if ((index == 3) || (index == 6)) {
    164                    aField.setEnabled(true);
    165                    bField.setEnabled(false);
    166                }
    167                else {
    168                    aField.setEnabled(false);
    169                    bField.setEnabled(false);
    170                }
    171            }
    172        });
    173
    174        Composite fieldComposite = new Composite(contentGroup, SWT.NONE);
    175        fieldComposite.setLayout(new GridLayout(2, false));
    176        fieldComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
    177
    178        Label label = new Label(fieldComposite, SWT.RIGHT);
    179        label.setFont(curFont);
    180        label.setText("a = ");
    181
    182        aField = new Text(fieldComposite, SWT.SINGLE | SWT.BORDER);
    183        GridData aFieldData = new GridData(SWT.FILL, SWT.FILL, true, false);
    184        aFieldData.minimumWidth = 100;
    185        aField.setLayoutData(aFieldData);
    186        aField.setFont(curFont);
    187        aField.setText("0");
    188        aField.setEnabled(false);
    189
    190        label = new Label(fieldComposite, SWT.RIGHT);
    191        label.setFont(curFont);
    192        label.setText("b = ");
    193
    194        bField = new Text(fieldComposite, SWT.SINGLE | SWT.BORDER);
    195        bField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
    196        bField.setFont(curFont);
    197        bField.setText("1");
    198        bField.setEnabled(false);
    199
    200        infoArea = new Text(contentGroup, SWT.MULTI | SWT.BORDER | SWT.WRAP);
    201        infoArea.setEditable(false);
    202        infoArea.setFont(curFont);
    203        infoArea.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_GRAY));
    204        GridData infoAreaData = new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1);
    205        infoAreaData.minimumHeight = 150;
    206        infoArea.setLayoutData(infoAreaData);
    207
    208        // Create Ok/Cancel button region
    209        Composite buttonComposite = new Composite(shell, SWT.NONE);
    210        buttonComposite.setLayout(new GridLayout(2, true));
    211        buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
    212
    213        Button okButton = new Button(buttonComposite, SWT.PUSH);
    214        okButton.setFont(curFont);
    215        okButton.setText("   &OK   ");
    216        okButton.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
    217        okButton.addSelectionListener(new SelectionAdapter() {
    218            @Override
    219            public void widgetSelected(SelectionEvent e) {
    220                isConverted = convertData();
    221
    222                shell.dispose();
    223            }
    224        });
    225
    226        Button cancelButton = new Button(buttonComposite, SWT.PUSH);
    227        cancelButton.setFont(curFont);
    228        cancelButton.setText(" &Cancel ");
    229        cancelButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, true, false));
    230        cancelButton.addSelectionListener(new SelectionAdapter() {
    231            @Override
    232            public void widgetSelected(SelectionEvent e) {
    233                isConverted = false;
    234
    235                shell.dispose();
    236            }
    237        });
    238
    239        shell.pack();
    240
    241        shell.addDisposeListener(new DisposeListener() {
    242            @Override
    243            public void widgetDisposed(DisposeEvent e) {
    244                if (curFont != null) curFont.dispose();
    245            }
    246        });
    247
    248        shell.setMinimumSize(shell.computeSize(SWT.DEFAULT, SWT.DEFAULT));
    249
    250        Rectangle parentBounds = parent.getBounds();
    251        Point shellSize = shell.getSize();
    252        shell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2),
    253                          (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2));
    254
    255        shell.open();
    256
    257        Display display = parent.getDisplay();
    258        while(!shell.isDisposed()) {
    259            if (!display.readAndDispatch())
    260                display.sleep();
    261        }
    262    }
    263
    264    private boolean convertData() {
    265        double a = 0, b = 1;
    266
    267        int index = functionList.getSelectionIndex();
    268
    269        try {
    270            if ((index == 0) || (index == 2)) {
    271                a = Double.parseDouble(aField.getText().trim());
    272                b = Double.parseDouble(bField.getText().trim());
    273            }
    274            else if (index == 3) {
    275                a = Double.parseDouble(aField.getText().trim());
    276            }
    277            else if (index == 6) {
    278                a = Integer.parseInt(aField.getText().trim());
    279                if (a <= 0) {
    280                    shell.getDisplay().beep();
    281                    Tools.showError(shell, "Convert", "a must be an integer greater than zero.");
    282                    return false;
    283                }
    284            }
    285        }
    286        catch (Exception ex) {
    287            shell.getDisplay().beep();
    288            Tools.showError(shell, "Convert", ex.getMessage());
    289            return false;
    290        }
    291
    292        int n = Array.getLength(dataValue);
    293        double value = 0, x = 0;
    294
    295        switch (NT) {
    296            case 'B':
    297                byte[] bdata = (byte[]) dataValue;
    298                for (int i = 0; i < n; i++) {
    299                    x = bdata[i];
    300                    value = y(index, x, a, b);
    301                    if ((value > Byte.MAX_VALUE) || (value < Byte.MIN_VALUE)) {
    302                        Tools.showError(shell, "Convert", "Invalid byte value: " + (long) value);
    303                        return false;
    304                    }
    305
    306                    bdata[i] = (byte) value;
    307                }
    308                break;
    309            case 'S':
    310                short[] sdata = (short[]) dataValue;
    311                for (int i = 0; i < n; i++) {
    312                    x = sdata[i];
    313                    value = y(index, x, a, b);
    314                    if ((value > Short.MAX_VALUE) || (value < Short.MIN_VALUE)) {
    315                        Tools.showError(shell, "Convert", "Invalid short value: " + (long) value);
    316                        return false;
    317                    }
    318
    319                    sdata[i] = (short) value;
    320                }
    321                break;
    322            case 'I':
    323                int[] idata = (int[]) dataValue;
    324                for (int i = 0; i < n; i++) {
    325                    x = idata[i];
    326                    value = y(index, x, a, b);
    327                    if ((value > Integer.MAX_VALUE) || (value < Integer.MIN_VALUE)) {
    328                        Tools.showError(shell, "Convert", "Invalid int value: " + (long) value);
    329                        return false;
    330                    }
    331
    332                    idata[i] = (int) value;
    333                }
    334                break;
    335            case 'J':
    336                long[] ldata = (long[]) dataValue;
    337                for (int i = 0; i < n; i++) {
    338                    x = ldata[i];
    339                    value = y(index, x, a, b);
    340                    if ((value > Long.MAX_VALUE) || (value < Long.MIN_VALUE)) {
    341                        Tools.showError(shell, "Convert", "Invalid long value: " + (long) value);
    342                        return false;
    343                    }
    344
    345                    ldata[i] = (long) value;
    346                }
    347                break;
    348            case 'F':
    349                float[] fdata = (float[]) dataValue;
    350                for (int i = 0; i < n; i++) {
    351                    x = fdata[i];
    352                    value = y(index, x, a, b);
    353                    if ((value > Float.MAX_VALUE) || (value < -Float.MAX_VALUE)
    354                        || (value == Float.NaN)) {
    355                        Tools.showError(shell, "Convert", "Invalid float value: " + value);
    356                        return false;
    357                    }
    358
    359                    fdata[i] = (float) value;
    360                }
    361                break;
    362            case 'D':
    363                double[] ddata = (double[]) dataValue;
    364                for (int i = 0; i < n; i++) {
    365                    x = ddata[i];
    366                    value = y(index, x, a, b);
    367                    if ((value > Double.MAX_VALUE) || (value < -Double.MAX_VALUE)
    368                        || (value == Double.NaN)) {
    369                        Tools.showError(shell, "Convert", "Invalid double value: " + value);
    370                        return false;
    371                    }
    372
    373                    ddata[i] = value;
    374                }
    375                break;
    376            default:
    377                break;
    378        }
    379
    380        return true;
    381    }
    382
    383    private double y(int index, double x, double a, double b) {
    384        double y = x;
    385
    386        switch (index) {
    387            case 0:
    388                if (x < a) {
    389                    y = a;
    390                }
    391                else if (x > b) {
    392                    y = b;
    393                }
    394                break;
    395            case 1:
    396                y = Math.abs(x);
    397                break;
    398            case 2:
    399                y = (a + b * x);
    400                break;
    401            case 3:
    402                y = Math.pow(x, a);
    403                break;
    404            case 4:
    405                y = Math.exp(x);
    406                break;
    407            case 5:
    408                y = Math.log(x);
    409                break;
    410            case 6:
    411                y = (Math.log(x) / Math.log(a));
    412                break;
    413            case 7:
    414                y = Math.sin(x);
    415                break;
    416            case 8:
    417                y = Math.cos(x);
    418                break;
    419            case 9:
    420                y = Math.tan(x);
    421                break;
    422            default:
    423                break;
    424        }
    425
    426        return y;
    427    }
    428
    429    /** @return true if the data is successfully converted. */
    430    public boolean isConverted() {
    431        return isConverted;
    432    }
    433}