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}