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.io.InputStream; 018import java.math.BigInteger; 019import java.net.URL; 020import java.net.URLClassLoader; 021import java.util.Iterator; 022import java.util.List; 023import java.util.Scanner; 024import java.util.StringTokenizer; 025 026import org.eclipse.swt.SWT; 027import org.eclipse.swt.browser.Browser; 028import org.eclipse.swt.events.DisposeEvent; 029import org.eclipse.swt.events.DisposeListener; 030import org.eclipse.swt.events.SelectionAdapter; 031import org.eclipse.swt.events.SelectionEvent; 032import org.eclipse.swt.graphics.Point; 033import org.eclipse.swt.graphics.Rectangle; 034import org.eclipse.swt.layout.GridData; 035import org.eclipse.swt.layout.GridLayout; 036import org.eclipse.swt.widgets.Button; 037import org.eclipse.swt.widgets.Combo; 038import org.eclipse.swt.widgets.Composite; 039import org.eclipse.swt.widgets.Dialog; 040import org.eclipse.swt.widgets.Display; 041import org.eclipse.swt.widgets.Label; 042import org.eclipse.swt.widgets.Shell; 043import org.eclipse.swt.widgets.Text; 044 045import hdf.object.Attribute; 046import hdf.object.Datatype; 047import hdf.object.Group; 048import hdf.object.HObject; 049import hdf.object.MetaDataContainer; 050import hdf.object.h5.H5CompoundAttr; 051import hdf.object.h5.H5Datatype; 052import hdf.object.h5.H5ScalarAttr; 053 054import hdf.view.Tools; 055import hdf.view.ViewProperties; 056 057/** 058 * NewScalarAttributeDialog displays components for adding a new attribute. 059 * 060 * @author Jordan T. Henderson 061 * @version 2.4 1/7/2016 062 */ 063public class NewScalarAttributeDialog extends NewDataObjectDialog { 064 065 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(NewScalarAttributeDialog.class); 066 067 /** the default length of a string attribute */ 068 public static final int DEFAULT_STRING_ATTRIBUTE_LENGTH = 256; 069 070 private Text currentSizeField; 071 072 private Combo rankChoice; 073 074 /** TextField for entering the name of the attribute */ 075 protected Text nameField; 076 077 /** 078 * Constructs a NewScalarAttributeDialog with specified object (dataset, group, or 079 * image) for the new attribute to be attached to. 080 * 081 * @param parent 082 * the parent shell of the dialog 083 * @param pObject 084 * the parent object which the new attribute is attached to. 085 * @param objs 086 * the list of all objects. 087 */ 088 public NewScalarAttributeDialog(Shell parent, HObject pObject, List<HObject> objs) { 089 super(parent, pObject, objs); 090 } 091 092 /** 093 * Open the NewScalarAttributeDialog for adding a new attribute. 094 */ 095 public void open() { 096 Shell parent = getParent(); 097 shell = new Shell(parent, SWT.SHELL_TRIM | SWT.APPLICATION_MODAL); 098 shell.setFont(curFont); 099 shell.setText("New Attribute..."); 100 shell.setImage(ViewProperties.getHdfIcon()); 101 shell.setLayout(new GridLayout(1, true)); 102 103 104 // Create Attribute name / Parent Object region 105 Composite fieldComposite = new Composite(shell, SWT.NONE); 106 fieldComposite.setLayout(new GridLayout(2, false)); 107 fieldComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 108 109 Label attributeNameLabel = new Label(fieldComposite, SWT.LEFT); 110 attributeNameLabel.setFont(curFont); 111 attributeNameLabel.setText("Attribute name: "); 112 113 nameField = new Text(fieldComposite, SWT.SINGLE | SWT.BORDER); 114 nameField.setFont(curFont); 115 GridData data = new GridData(SWT.FILL, SWT.FILL, true, false); 116 117 data.minimumWidth = 250; 118 nameField.setLayoutData(data); 119 120 Label parentObjectLabel = new Label(fieldComposite, SWT.LEFT); 121 parentObjectLabel.setFont(curFont); 122 parentObjectLabel.setText("Parent Object: "); 123 124 // Create Datatype region 125 createDatatypeWidget(); 126 127 // Create Dataspace region 128 org.eclipse.swt.widgets.Group dataspaceGroup = new org.eclipse.swt.widgets.Group(shell, SWT.NONE); 129 dataspaceGroup.setFont(curFont); 130 dataspaceGroup.setText("Dataspace"); 131 dataspaceGroup.setLayout(new GridLayout(3, true)); 132 dataspaceGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 133 134 Label label = new Label(dataspaceGroup, SWT.LEFT); 135 label.setFont(curFont); 136 label.setText("No. of dimensions"); 137 138 label = new Label(dataspaceGroup, SWT.LEFT); 139 label.setFont(curFont); 140 label.setText("Current size"); 141 142 // Dummy label 143 label = new Label(dataspaceGroup, SWT.LEFT); 144 label.setFont(curFont); 145 label.setText(""); 146 147 rankChoice = new Combo(dataspaceGroup, SWT.DROP_DOWN | SWT.READ_ONLY); 148 rankChoice.setFont(curFont); 149 rankChoice.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 150 rankChoice.addSelectionListener(new SelectionAdapter() { 151 @Override 152 public void widgetSelected(SelectionEvent e) { 153 int rank = rankChoice.getSelectionIndex() + 1; 154 StringBuilder currentSizeStr = new StringBuilder("1"); 155 156 for (int i = 1; i < rank; i++) { 157 currentSizeStr.append(" x 1"); 158 } 159 160 currentSizeField.setText(currentSizeStr.toString()); 161 162 String currentStr = currentSizeField.getText(); 163 int idx = currentStr.lastIndexOf('x'); 164 } 165 }); 166 167 for (int i = 1; i < 33; i++) { 168 rankChoice.add(String.valueOf(i)); 169 } 170 rankChoice.select(1); 171 172 currentSizeField = new Text(dataspaceGroup, SWT.SINGLE | SWT.BORDER); 173 currentSizeField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 174 currentSizeField.setFont(curFont); 175 currentSizeField.setText("1 x 1"); 176 177 // Create Ok/Cancel/Help button region 178 Composite buttonComposite = new Composite(shell, SWT.NONE); 179 buttonComposite.setLayout(new GridLayout(3, false)); 180 buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 181 182 Button okButton = new Button(buttonComposite, SWT.PUSH); 183 okButton.setFont(curFont); 184 okButton.setText(" &OK "); 185 okButton.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false)); 186 okButton.addSelectionListener(new SelectionAdapter() { 187 @Override 188 public void widgetSelected(SelectionEvent e) { 189 if (createAttribute()) { 190 shell.dispose(); 191 } 192 } 193 }); 194 195 Button cancelButton = new Button(buttonComposite, SWT.PUSH); 196 cancelButton.setFont(curFont); 197 cancelButton.setText(" &Cancel "); 198 cancelButton.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, false, false)); 199 cancelButton.addSelectionListener(new SelectionAdapter() { 200 @Override 201 public void widgetSelected(SelectionEvent e) { 202 newObject = null; 203 shell.dispose(); 204 } 205 }); 206 207 Button helpButton = new Button(buttonComposite, SWT.PUSH); 208 helpButton.setFont(curFont); 209 helpButton.setText(" &Help "); 210 helpButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, true, false)); 211 helpButton.addSelectionListener(new SelectionAdapter() { 212 @Override 213 public void widgetSelected(SelectionEvent e) { 214 new HelpDialog(shell).open(); 215 } 216 }); 217 218 shell.pack(); 219 220 shell.addDisposeListener(new DisposeListener() { 221 @Override 222 public void widgetDisposed(DisposeEvent e) { 223 if (curFont != null) curFont.dispose(); 224 } 225 }); 226 227 shell.setMinimumSize(shell.computeSize(SWT.DEFAULT, SWT.DEFAULT)); 228 229 Rectangle parentBounds = parent.getBounds(); 230 Point shellSize = shell.getSize(); 231 shell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2), 232 (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2)); 233 234 shell.open(); 235 236 Display display = shell.getDisplay(); 237 while (!shell.isDisposed()) 238 if (!display.readAndDispatch()) 239 display.sleep(); 240 } 241 242 /** Check if the dim size is valid */ 243 private void checkDimSize() { 244 String dimStr = currentSizeField.getText(); 245 StringTokenizer stDim = new StringTokenizer(dimStr, "x"); 246 247 int rank = stDim.countTokens(); 248 long dim = 0; 249 for (int i = 0; i < rank; i++) { 250 String token = stDim.nextToken().trim(); 251 252 token = token.toLowerCase(); 253 try { 254 dim = Long.parseLong(token); 255 } 256 catch (NumberFormatException ex) { 257 shell.getDisplay().beep(); 258 Tools.showError(shell, "Check", "Invalid dimension size: " + dimStr); 259 return; 260 } 261 } // (int i = 0; i < rank; i++) 262 } 263 264 @SuppressWarnings("unchecked") 265 private boolean createAttribute() { 266 String attrName = null; 267 int rank = -1; 268 long[] dims; 269 270 attrName = nameField.getText(); 271 if (attrName != null) { 272 attrName = attrName.trim(); 273 } 274 275 if ((attrName == null) || (attrName.length() < 1)) { 276 shell.getDisplay().beep(); 277 Tools.showError(shell, "Create", "Attribute name is not specified."); 278 return false; 279 } 280 281 rank = rankChoice.getSelectionIndex() + 1; 282 StringTokenizer st = new StringTokenizer(currentSizeField.getText(), "x"); 283 if (st.countTokens() < rank) { 284 shell.getDisplay().beep(); 285 Tools.showError(shell, "Create", "Number of values in the current dimension size is less than " + rank); 286 return false; 287 } 288 289 long lsize = 1; // The total size 290 long l = 0; 291 dims = new long[rank]; 292 String token = null; 293 for (int i = 0; i < rank; i++) { 294 token = st.nextToken().trim(); 295 try { 296 l = Long.parseLong(token); 297 } 298 catch (NumberFormatException ex) { 299 shell.getDisplay().beep(); 300 Tools.showError(shell, "Create", "Invalid dimension size: " + currentSizeField.getText()); 301 return false; 302 } 303 304 if (l <= 0) { 305 shell.getDisplay().beep(); 306 Tools.showError(shell, "Create", "Dimension size must be greater than zero."); 307 return false; 308 } 309 310 dims[i] = l; 311 lsize *= l; 312 } 313 log.trace("Create: lsize={}", lsize); 314 315 Attribute attr = null; 316 try { 317 H5Datatype datatype = (H5Datatype)createNewDatatype(null); 318 319 if (datatype.isCompound()) 320 attr = (Attribute)new H5CompoundAttr(parentObj, attrName, datatype, dims); 321 else 322 attr = (Attribute)new H5ScalarAttr(parentObj, attrName, datatype, dims); 323 Object value = H5Datatype.allocateArray(datatype, (int) lsize); 324 attr.setAttributeData(value); 325 326 log.trace("writeMetadata() via write()"); 327 attr.writeAttribute(); 328 } 329 catch (Exception ex) { 330 Tools.showError(shell, "Create", ex.getMessage()); 331 log.debug("createAttribute(): ", ex); 332 return false; 333 } 334 335 newObject = (HObject)attr; 336 337 return true; 338 } 339 340 private class HelpDialog extends Dialog { 341 private Shell helpShell; 342 343 public HelpDialog(Shell parent) { 344 super(parent, SWT.APPLICATION_MODAL); 345 } 346 347 public void open() { 348 Shell parent = getParent(); 349 helpShell = new Shell(parent, SWT.TITLE | SWT.CLOSE | 350 SWT.RESIZE | SWT.BORDER | SWT.APPLICATION_MODAL); 351 helpShell.setFont(curFont); 352 helpShell.setText("Create New Attribute"); 353 helpShell.setImage(ViewProperties.getHdfIcon()); 354 helpShell.setLayout(new GridLayout(1, true)); 355 356 // Try to create a Browser on platforms that support it 357 try { 358 Browser browser = new Browser(helpShell, SWT.NONE); 359 browser.setFont(curFont); 360 browser.setBounds(0, 0, 500, 500); 361 browser.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 362 363 if (ClassLoader.getSystemResource("hdf/view/HDFView.class").toString().startsWith("jar")) { 364 // Attempt to load HTML help file from jar 365 try (InputStream in = getClass().getClassLoader().getResourceAsStream("hdf/view/NewAttrHelp.html")) { 366 Scanner scan = new Scanner(in); 367 StringBuilder buffer = new StringBuilder(); 368 while(scan.hasNextLine()) { 369 buffer.append(scan.nextLine()); 370 } 371 372 browser.setText(buffer.toString()); 373 374 scan.close(); 375 } 376 catch (Exception e) { 377 StringBuilder buff = new StringBuilder(); 378 buff.append("<html>") 379 .append("<body>") 380 .append("ERROR: cannot load help information.") 381 .append("</body>") 382 .append("</html>"); 383 browser.setText(buff.toString(), true); 384 } 385 } 386 else { 387 try { 388 URL url = null, url2 = null, url3 = null; 389 String rootPath = ViewProperties.getViewRoot(); 390 391 try { 392 url = new URL("file://" + rootPath + "/HDFView.jar"); 393 } 394 catch (java.net.MalformedURLException mfu) { 395 log.debug("help information:", mfu); 396 } 397 398 try { 399 url2 = new URL("file://" + rootPath + "/"); 400 } 401 catch (java.net.MalformedURLException mfu) { 402 log.debug("help information:", mfu); 403 } 404 405 try { 406 url3 = new URL("file://" + rootPath + "/src/"); 407 } 408 catch (java.net.MalformedURLException mfu) { 409 log.debug("help information:", mfu); 410 } 411 412 URL uu[] = { url, url2, url3 }; 413 try (URLClassLoader cl = new URLClassLoader(uu)) { 414 URL u = cl.findResource("hdf/view/NewAttrHelp.html"); 415 416 browser.setUrl(u.toString()); 417 } 418 catch (Exception ex) { 419 log.trace("URLClassLoader failed:", ex); 420 } 421 } 422 catch (Exception e) { 423 StringBuilder buff = new StringBuilder(); 424 buff.append("<html>") 425 .append("<body>") 426 .append("ERROR: cannot load help information.") 427 .append("</body>") 428 .append("</html>"); 429 browser.setText(buff.toString(), true); 430 } 431 } 432 433 Button okButton = new Button(helpShell, SWT.PUSH); 434 okButton.setFont(curFont); 435 okButton.setText(" &OK "); 436 okButton.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, true, false)); 437 okButton.addSelectionListener(new SelectionAdapter() { 438 @Override 439 public void widgetSelected(SelectionEvent e) { 440 helpShell.dispose(); 441 } 442 }); 443 444 helpShell.pack(); 445 446 helpShell.setSize(new Point(500, 500)); 447 448 Rectangle parentBounds = parent.getBounds(); 449 Point shellSize = helpShell.getSize(); 450 helpShell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2), 451 (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2)); 452 453 helpShell.open(); 454 455 Display display = parent.getDisplay(); 456 while(!helpShell.isDisposed()) { 457 if (!display.readAndDispatch()) 458 display.sleep(); 459 } 460 } 461 catch (Error er) { 462 // Try opening help link in external browser if platform 463 // doesn't support SWT browser 464 Tools.showError(shell, "Browser support", 465 "Platform doesn't support Browser. Opening external link in web browser..."); 466 467 //TODO: Add support for launching in external browser 468 } 469 catch (Exception ex) { 470 log.debug("Open New Attribute Help failure: ", ex); 471 } 472 } 473 } 474 475 /** @return the new attribute created. */ 476 public Attribute getAttribute() { 477 return (Attribute)newObject; 478 } 479}