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