    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.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    public void open() {
    126        Shell parent = getParent();
    127        shell = new Shell(parent, SWT.SHELL_TRIM | SWT.APPLICATION_MODAL);
    128        shell.setFont(curFont);
    129        shell.setText("Convert Data...");
    130        shell.setImage(ViewProperties.getHdfIcon());
    131        shell.setLayout(new GridLayout(1, true));
    132
    133        // Create content region
    134        org.eclipse.swt.widgets.Group contentGroup = new org.eclipse.swt.widgets.Group(shell, SWT.NONE);
    135        contentGroup.setFont(curFont);
    136        contentGroup.setText("Converting Data With A Mathematic Function");
    137        contentGroup.setLayout(new GridLayout(2, false));
    138        contentGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
    139
    140        String[] functionNames = { "[a, b]", "abs (x)", "a + b * x",
    141                "pow (x, a)", "exp (x)", "ln (x)", "log (a, x)", "sin (x)",
    142                "cos (x)", "tan (x)" };
    143
    144        functionList = new List(contentGroup, SWT.SINGLE | SWT.BORDER);
    145        functionList.setFont(curFont);
    146        functionList.setItems(functionNames);
    147        GridData functionListData = new GridData(SWT.FILL, SWT.FILL, true, false);
    148        functionListData.minimumWidth = 350;
    149        functionList.setLayoutData(functionListData);
    150        functionList.addSelectionListener(new SelectionAdapter() {
    151            @Override
    152            public void widgetSelected(SelectionEvent e) {
    153                int index = functionList.getSelectionIndex();
    154                infoArea.setText(functionDescription[index]);
    155
    156                if ((index == 0) || (index == 2)) {
    157                    aField.setEnabled(true);
    158                    bField.setEnabled(true);
    159                }
    160                else if ((index == 3) || (index == 6)) {
    161                    aField.setEnabled(true);
    162                    bField.setEnabled(false);
    163                }
    164                else {
    165                    aField.setEnabled(false);
    166                    bField.setEnabled(false);
    167                }
    168            }
    169        });
    170
    171        Composite fieldComposite = new Composite(contentGroup, SWT.NONE);
    172        fieldComposite.setLayout(new GridLayout(2, false));
    173        fieldComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
    174
    175        Label label = new Label(fieldComposite, SWT.RIGHT);
    176        label.setFont(curFont);
    177        label.setText("a = ");
    178
    179        aField = new Text(fieldComposite, SWT.SINGLE | SWT.BORDER);
    180        GridData aFieldData = new GridData(SWT.FILL, SWT.FILL, true, false);
    181        aFieldData.minimumWidth = 100;
    182        aField.setLayoutData(aFieldData);
    183        aField.setFont(curFont);
    184        aField.setText("0");
    185        aField.setEnabled(false);
    186
    187        label = new Label(fieldComposite, SWT.RIGHT);
    188        label.setFont(curFont);
    189        label.setText("b = ");
    190
    191        bField = new Text(fieldComposite, SWT.SINGLE | SWT.BORDER);
    192        bField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
    193        bField.setFont(curFont);
    194        bField.setText("1");
    195        bField.setEnabled(false);
    196
    197        infoArea = new Text(contentGroup, SWT.MULTI | SWT.BORDER | SWT.WRAP);
    198        infoArea.setEditable(false);
    199        infoArea.setFont(curFont);
    200        infoArea.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_GRAY));
    201        GridData infoAreaData = new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1);
    202        infoAreaData.minimumHeight = 150;
    203        infoArea.setLayoutData(infoAreaData);
    204
    205        // Create Ok/Cancel button region
    206        Composite buttonComposite = new Composite(shell, SWT.NONE);
    207        buttonComposite.setLayout(new GridLayout(2, true));
    208        buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
    209
    210        Button okButton = new Button(buttonComposite, SWT.PUSH);
    211        okButton.setFont(curFont);
    212        okButton.setText("   &OK   ");
    213        okButton.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false));
    214        okButton.addSelectionListener(new SelectionAdapter() {
    215            @Override
    216            public void widgetSelected(SelectionEvent e) {
    217                isConverted = convertData();
    218
    219                shell.dispose();
    220            }
    221        });
    222
    223        Button cancelButton = new Button(buttonComposite, SWT.PUSH);
    224        cancelButton.setFont(curFont);
    225        cancelButton.setText(" &Cancel ");
    226        cancelButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, true, false));
    227        cancelButton.addSelectionListener(new SelectionAdapter() {
    228            @Override
    229            public void widgetSelected(SelectionEvent e) {
    230                isConverted = false;
    231
    232                shell.dispose();
    233            }
    234        });
    235
    236        shell.pack();
    237
    238        shell.addDisposeListener(new DisposeListener() {
    239            @Override
    240            public void widgetDisposed(DisposeEvent e) {
    241                if (curFont != null) curFont.dispose();
    242            }
    243        });
    244
    245        shell.setMinimumSize(shell.computeSize(SWT.DEFAULT, SWT.DEFAULT));
    246
    247        Rectangle parentBounds = parent.getBounds();
    248        Point shellSize = shell.getSize();
    249        shell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2),
    250                          (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2));
    251
    252        shell.open();
    253
    254        Display display = parent.getDisplay();
    255        while(!shell.isDisposed()) {
    256            if (!display.readAndDispatch())
    257                display.sleep();
    258        }
    259    }
    260
    261    private boolean convertData() {
    262        double a = 0, b = 1;
    263
    264        int index = functionList.getSelectionIndex();
    265
    266        try {
    267            if ((index == 0) || (index == 2)) {
    268                a = Double.parseDouble(aField.getText().trim());
    269                b = Double.parseDouble(bField.getText().trim());
    270            }
    271            else if (index == 3) {
    272                a = Double.parseDouble(aField.getText().trim());
    273            }
    274            else if (index == 6) {
    275                a = Integer.parseInt(aField.getText().trim());
    276                if (a <= 0) {
    277                    shell.getDisplay().beep();
    278                    Tools.showError(shell, "Convert", "a must be an integer greater than zero.");
    279                    return false;
    280                }
    281            }
    282        }
    283        catch (Exception ex) {
    284            shell.getDisplay().beep();
    285            Tools.showError(shell, "Convert", ex.getMessage());
    286            return false;
    287        }
    288
    289        int n = Array.getLength(dataValue);
    290        double value = 0, x = 0;
    291
    292        switch (NT) {
    293            case 'B':
    294                byte[] bdata = (byte[]) dataValue;
    295                for (int i = 0; i < n; i++) {
    296                    x = bdata[i];
    297                    value = y(index, x, a, b);
    298                    if ((value > Byte.MAX_VALUE) || (value < Byte.MIN_VALUE)) {
    299                        Tools.showError(shell, "Convert", "Invalid byte value: " + (long) value);
    300                        return false;
    301                    }
    302
    303                    bdata[i] = (byte) value;
    304                }
    305                break;
    306            case 'S':
    307                short[] sdata = (short[]) dataValue;
    308                for (int i = 0; i < n; i++) {
    309                    x = sdata[i];
    310                    value = y(index, x, a, b);
    311                    if ((value > Short.MAX_VALUE) || (value < Short.MIN_VALUE)) {
    312                        Tools.showError(shell, "Convert", "Invalid short value: " + (long) value);
    313                        return false;
    314                    }
    315
    316                    sdata[i] = (short) value;
    317                }
    318                break;
    319            case 'I':
    320                int[] idata = (int[]) dataValue;
    321                for (int i = 0; i < n; i++) {
    322                    x = idata[i];
    323                    value = y(index, x, a, b);
    324                    if ((value > Integer.MAX_VALUE) || (value < Integer.MIN_VALUE)) {
    325                        Tools.showError(shell, "Convert", "Invalid int value: " + (long) value);
    326                        return false;
    327                    }
    328
    329                    idata[i] = (int) value;
    330                }
    331                break;
    332            case 'J':
    333                long[] ldata = (long[]) dataValue;
    334                for (int i = 0; i < n; i++) {
    335                    x = ldata[i];
    336                    value = y(index, x, a, b);
    337                    if ((value > Long.MAX_VALUE) || (value < Long.MIN_VALUE)) {
    338                        Tools.showError(shell, "Convert", "Invalid long value: " + (long) value);
    339                        return false;
    340                    }
    341
    342                    ldata[i] = (long) value;
    343                }
    344                break;
    345            case 'F':
    346                float[] fdata = (float[]) dataValue;
    347                for (int i = 0; i < n; i++) {
    348                    x = fdata[i];
    349                    value = y(index, x, a, b);
    350                    if ((value > Float.MAX_VALUE) || (value < -Float.MAX_VALUE)
    351                        || (value == Float.NaN)) {
    352                        Tools.showError(shell, "Convert", "Invalid float value: " + value);
    353                        return false;
    354                    }
    355
    356                    fdata[i] = (float) value;
    357                }
    358                break;
    359            case 'D':
    360                double[] ddata = (double[]) dataValue;
    361                for (int i = 0; i < n; i++) {
    362                    x = ddata[i];
    363                    value = y(index, x, a, b);
    364                    if ((value > Double.MAX_VALUE) || (value < -Double.MAX_VALUE)
    365                        || (value == Double.NaN)) {
    366                        Tools.showError(shell, "Convert", "Invalid double value: " + value);
    367                        return false;
    368                    }
    369
    370                    ddata[i] = value;
    371                }
    372                break;
    373            default:
    374                break;
    375        }
    376
    377        return true;
    378    }
    379
    380    private double y(int index, double x, double a, double b) {
    381        double y = x;
    382
    383        switch (index) {
    384            case 0:
    385                if (x < a) {
    386                    y = a;
    387                }
    388                else if (x > b) {
    389                    y = b;
    390                }
    391                break;
    392            case 1:
    393                y = Math.abs(x);
    394                break;
    395            case 2:
    396                y = (a + b * x);
    397                break;
    398            case 3:
    399                y = Math.pow(x, a);
    400                break;
    401            case 4:
    402                y = Math.exp(x);
    403                break;
    404            case 5:
    405                y = Math.log(x);
    406                break;
    407            case 6:
    408                y = (Math.log(x) / Math.log(a));
    409                break;
    410            case 7:
    411                y = Math.sin(x);
    412                break;
    413            case 8:
    414                y = Math.cos(x);
    415                break;
    416            case 9:
    417                y = Math.tan(x);
    418                break;
    419            default:
    420                break;
    421        }
    422
    423        return y;
    424    }
    425
    426    /** @return true if the data is successfully converted. */
    427    public boolean isConverted() {
    428        return isConverted;
    429    }
    430}