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 http://hdfgroup.org/products/hdf-java/doc/Copyright.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;
016
017import java.awt.BorderLayout;
018import java.awt.Dimension;
019import java.awt.GridLayout;
020import java.awt.Point;
021import java.awt.Toolkit;
022import java.awt.event.ActionEvent;
023import java.awt.event.ActionListener;
024import java.awt.event.KeyEvent;
025import java.lang.reflect.Array;
026
027import javax.swing.BorderFactory;
028import javax.swing.JButton;
029import javax.swing.JDialog;
030import javax.swing.JFrame;
031import javax.swing.JLabel;
032import javax.swing.JList;
033import javax.swing.JOptionPane;
034import javax.swing.JPanel;
035import javax.swing.JScrollPane;
036import javax.swing.JTextArea;
037import javax.swing.JTextField;
038import javax.swing.ListSelectionModel;
039import javax.swing.border.TitledBorder;
040import javax.swing.event.ListSelectionEvent;
041import javax.swing.event.ListSelectionListener;
042
043/**
044 * MathConversionDialog shows a message dialog requesting user input for math
045 * conversion.
046 * 
047 * @author Peter X. Cao
048 * @version 2.4 9/6/2007
049 */
050public class MathConversionDialog extends JDialog implements ActionListener,
051        ListSelectionListener {
052    private static final long serialVersionUID = 5136554941147830371L;
053
054    private JTextField aField, bField;
055
056    private JTextArea infoArea;
057
058    private JList functionList;
059
060    private Object dataValue;
061
062    private char NT;
063
064    private final Toolkit toolkit;
065
066    private String[] functionDescription;
067
068    private boolean isConverted;
069
070    /**
071     * Constructs MathConversionDialog.
072     * 
073     * @param owner
074     *            the owner of the input
075     * @param data
076     *            the data array to convert.
077     */
078    public MathConversionDialog(JFrame owner, Object data) {
079        super(owner, "Convert Data...", true);
080
081        toolkit = Toolkit.getDefaultToolkit();
082        isConverted = false;
083        dataValue = data;
084        NT = ' ';
085
086        String cName = data.getClass().getName();
087        int cIndex = cName.lastIndexOf("[");
088        if (cIndex >= 0) {
089            NT = cName.charAt(cIndex + 1);
090        }
091
092        String[] functionNames = { "[a, b]", "abs (x)", "a + b * x",
093                "pow (x, a)", "exp (x)", "ln (x)", "log (a, x)", "sin (x)",
094                "cos (x)", "tan (x)" };
095        functionList = new JList(functionNames);
096        functionList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
097        functionList.addListSelectionListener(this);
098
099        String[] tmpStrs = {
100                "The filter by lower and upper bounds. x=a if x<a; x=b if x>b."
101                        + "\ne.g.\n x=5, [0, 127]=5\n x=-5, [0, 127]=0\n x=255, [0, 127]=127.",
102                "The absolute value of a number, the number without its sign."
103                        + "\ne.g.\n abs(5)=5\n abs(-5)=5.",
104                "Linear function." + "\ne.g.\n a=5, b=2, x=2.5, a+b*x=10.",
105                "The result of a number raised to power of a."
106                        + "\ne.g.\n x=2.5, a=10, pow(x, a)=9536.743\n x=25, a=0.5, pow(x, a)=5.",
107                "The exponential number e (i.e., 2.718...) raised to the power of x."
108                        + "\ne.g.\n exp(5.0)=148.41316\n exp(5.5)=244.69193",
109                "The natural logarithm (base e) of x."
110                        + "\ne.g.\n ln(20.085541)=3\n ln(10)=2.302585",
111                "The logarithm of x to the base of a, \"a\" must be an integer > 0."
112                        + "\ne.g.\n log(10, 2)=3.321928\n log(2, 10)=0.30103",
113                "The trigonometric sine of angle x in radians."
114                        + "\ne.g.\n sin(0.523599)=0.5\n sin(1.047198)=0.866025",
115                "The trigonometric cosine of angle x in radians."
116                        + "\ne.g.\n cos(0.523599)=0.866025\n cos(1.047198)=0.5",
117                "The trigonometric tangent of angle x in radians."
118                        + "\ne.g.\n tan(0.785398)=1\n tan(1.047198)=1.732051" };
119
120        functionDescription = tmpStrs;
121
122        JPanel contentPane = (JPanel) getContentPane();
123        contentPane.setLayout(new BorderLayout(5, 5));
124        contentPane.setBorder(BorderFactory.createEmptyBorder(10, 5, 5, 5));
125        int w = 500 + (ViewProperties.getFontSize() - 12) * 15;
126        int h = 300 + (ViewProperties.getFontSize() - 12) * 10;
127        contentPane.setPreferredSize(new Dimension(w, h));
128
129        JButton okButton = new JButton("   Ok   ");
130        okButton.setActionCommand("Ok");
131        okButton.setMnemonic(KeyEvent.VK_O);
132        okButton.addActionListener(this);
133
134        JButton cancelButton = new JButton("Cancel");
135        cancelButton.setMnemonic(KeyEvent.VK_C);
136        cancelButton.setActionCommand("Cancel");
137        cancelButton.addActionListener(this);
138
139        // set OK and CANCEL buttons
140        JPanel buttonPanel = new JPanel();
141        buttonPanel.add(okButton);
142        buttonPanel.add(cancelButton);
143        contentPane.add(buttonPanel, BorderLayout.SOUTH);
144
145        // set name, parent, width and height panel
146        JPanel centerP = new JPanel();
147        centerP.setLayout(new BorderLayout(10, 10));
148        JScrollPane scroller = new JScrollPane(functionList);
149        centerP.add(scroller, BorderLayout.CENTER);
150
151        JPanel tmpP = new JPanel();
152        tmpP.setLayout(new BorderLayout(5, 5));
153
154        JPanel tmpP0 = new JPanel();
155        tmpP0.setLayout(new GridLayout(4, 1, 5, 5));
156        tmpP0.add(new JLabel("a = "));
157        tmpP0.add(new JLabel("b = "));
158        tmpP0.add(new JLabel("                     "));
159        tmpP0.add(new JLabel("                     "));
160        tmpP.add(tmpP0, BorderLayout.WEST);
161
162        tmpP0 = new JPanel();
163        tmpP0.setLayout(new GridLayout(4, 1, 5, 5));
164        tmpP0.add(aField = new JTextField("0"));
165        tmpP0.add(bField = new JTextField("1"));
166        tmpP0.add(new JLabel("                     "));
167        tmpP0.add(new JLabel("                     "));
168        tmpP.add(tmpP0, BorderLayout.CENTER);
169
170        centerP.add(tmpP, BorderLayout.EAST);
171        
172        tmpP0 = new JPanel();
173        tmpP0.setLayout(new BorderLayout());
174        tmpP0.add(infoArea = new JTextArea(4, 80), BorderLayout.CENTER);
175        infoArea.setEditable(false);
176        infoArea.setLineWrap(true);
177        infoArea.setBackground(java.awt.Color.lightGray);
178        infoArea.setWrapStyleWord(true);
179
180        centerP.setBorder(new TitledBorder(
181                "Converting Data With A Mathematic Function"));
182        centerP.add(tmpP0, BorderLayout.SOUTH);
183        aField.setEnabled(false);
184        bField.setEnabled(false);
185
186        contentPane.add(centerP, BorderLayout.CENTER);
187
188        // locate the H5Property dialog
189        Point l = owner.getLocation();
190        l.x += 250;
191        l.y += 80;
192        setLocation(l);
193        validate();
194        pack();
195    }
196
197    private boolean convertData() {
198        double a = 0, b = 1;
199
200        int index = functionList.getSelectedIndex();
201        try {
202            if ((index == 0) || (index == 2)) {
203                a = Double.parseDouble(aField.getText().trim());
204                b = Double.parseDouble(bField.getText().trim());
205            }
206            else if (index == 3) {
207                a = Double.parseDouble(aField.getText().trim());
208            }
209            else if (index == 6) {
210                a = Integer.parseInt(aField.getText().trim());
211                if (a <= 0) {
212                    toolkit.beep();
213                    JOptionPane.showMessageDialog(this,
214                            "a must be an integer greater than zero.",
215                            getTitle(), JOptionPane.ERROR_MESSAGE);
216                    return false;
217                }
218            }
219        }
220        catch (Exception ex) {
221            toolkit.beep();
222            JOptionPane.showMessageDialog(this, ex.getMessage(), getTitle(),
223                    JOptionPane.ERROR_MESSAGE);
224            return false;
225        }
226
227        int n = Array.getLength(dataValue);
228        double value = 0, x = 0;
229
230        switch (NT) {
231        case 'B':
232            byte[] bdata = (byte[]) dataValue;
233            for (int i = 0; i < n; i++) {
234                x = bdata[i];
235                value = y(index, x, a, b);
236                if ((value > Byte.MAX_VALUE) || (value < Byte.MIN_VALUE)) {
237                    JOptionPane.showMessageDialog(this, "Invalid byte value: "
238                            + (long) value, getTitle(),
239                            JOptionPane.ERROR_MESSAGE);
240                    return false;
241                }
242
243                bdata[i] = (byte) value;
244            } // for (int i=0; i<n; i++)
245            break;
246        case 'S':
247            short[] sdata = (short[]) dataValue;
248            for (int i = 0; i < n; i++) {
249                x = sdata[i];
250                value = y(index, x, a, b);
251                if ((value > Short.MAX_VALUE) || (value < Short.MIN_VALUE)) {
252                    JOptionPane.showMessageDialog(this, "Invalid short value: "
253                            + (long) value, getTitle(),
254                            JOptionPane.ERROR_MESSAGE);
255                    return false;
256                }
257
258                sdata[i] = (short) value;
259            } // for (int i=0; i<n; i++)
260            break;
261        case 'I':
262            int[] idata = (int[]) dataValue;
263            for (int i = 0; i < n; i++) {
264                x = idata[i];
265                value = y(index, x, a, b);
266                if ((value > Integer.MAX_VALUE) || (value < Integer.MIN_VALUE)) {
267                    JOptionPane.showMessageDialog(this, "Invalid int value: "
268                            + (long) value, getTitle(),
269                            JOptionPane.ERROR_MESSAGE);
270                    return false;
271                }
272
273                idata[i] = (int) value;
274            } // for (int i=0; i<n; i++)
275            break;
276        case 'J':
277            long[] ldata = (long[]) dataValue;
278            for (int i = 0; i < n; i++) {
279                x = ldata[i];
280                value = y(index, x, a, b);
281                if ((value > Long.MAX_VALUE) || (value < Long.MIN_VALUE)) {
282                    JOptionPane.showMessageDialog(this, "Invalid long value: "
283                            + (long) value, getTitle(),
284                            JOptionPane.ERROR_MESSAGE);
285                    return false;
286                }
287
288                ldata[i] = (long) value;
289            } // for (int i=0; i<n; i++)
290            break;
291        case 'F':
292            float[] fdata = (float[]) dataValue;
293            for (int i = 0; i < n; i++) {
294                x = fdata[i];
295                value = y(index, x, a, b);
296                if ((value > Float.MAX_VALUE) || (value < -Float.MAX_VALUE)
297                        || (value == Float.NaN)) {
298                    JOptionPane.showMessageDialog(this, "Invalid float value: "
299                            + value, getTitle(), JOptionPane.ERROR_MESSAGE);
300                    return false;
301                }
302
303                fdata[i] = (float) value;
304            } // for (int i=0; i<n; i++)
305            break;
306        case 'D':
307            double[] ddata = (double[]) dataValue;
308            for (int i = 0; i < n; i++) {
309                x = ddata[i];
310                value = y(index, x, a, b);
311                if ((value > Double.MAX_VALUE) || (value < -Double.MAX_VALUE)
312                        || (value == Double.NaN)) {
313                    JOptionPane.showMessageDialog(this,
314                            "Invalid double value: " + value, getTitle(),
315                            JOptionPane.ERROR_MESSAGE);
316                    return false;
317                }
318
319                ddata[i] = value;
320            } // for (int i=0; i<n; i++)
321            break;
322        default:
323            break;
324        }
325
326        return true;
327    }
328
329    public void actionPerformed(ActionEvent e) {
330        Object source = e.getSource();
331        String cmd = e.getActionCommand();
332
333        if (cmd.equals("Ok")) {
334            isConverted = convertData();
335            // if (isConverted)
336            dispose();
337        }
338        if (cmd.equals("Cancel")) {
339            isConverted = false;
340            dispose();
341        }
342    }
343
344    public void valueChanged(ListSelectionEvent e) {
345        if (e.getValueIsAdjusting()) {
346            return;
347        }
348
349        if (!e.getSource().equals(functionList)) {
350            return;
351        }
352
353        if (functionList.isSelectionEmpty()) {
354            return;
355        }
356
357        int index = functionList.getSelectedIndex();
358        infoArea.setText(functionDescription[index]);
359
360        if ((index == 0) || (index == 2)) {
361            aField.setEnabled(true);
362            bField.setEnabled(true);
363        }
364        else if ((index == 3) || (index == 6)) {
365            aField.setEnabled(true);
366            bField.setEnabled(false);
367        }
368        else {
369            aField.setEnabled(false);
370            bField.setEnabled(false);
371        }
372    }
373
374    private double y(int index, double x, double a, double b) {
375        double y = x;
376        switch (index) {
377        case 0:
378            if (x < a) {
379                y = a;
380            }
381            else if (x > b) {
382                y = b;
383            }
384            break;
385        case 1:
386            y = Math.abs(x);
387            break;
388        case 2:
389            y = (a + b * x);
390            break;
391        case 3:
392            y = Math.pow(x, a);
393            break;
394        case 4:
395            y = Math.exp(x);
396            break;
397        case 5:
398            y = Math.log(x);
399            break;
400        case 6:
401            y = (Math.log(x) / Math.log(a));
402            break;
403        case 7:
404            y = Math.sin(x);
405            break;
406        case 8:
407            y = Math.cos(x);
408            break;
409        case 9:
410            y = Math.tan(x);
411            break;
412        default:
413            y = x;
414            break;
415        }
416
417        return y;
418    }
419
420    /**
421     * Returns true if the data is successfully converted.
422     * 
423     * @return true if the data is successfully converted; false otherwise
424     */
425    public boolean isConverted() {
426        return isConverted;
427    }
428
429}