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