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.MetaDataView; 016 017import java.io.File; 018import java.lang.reflect.Array; 019import java.math.BigInteger; 020import java.util.ArrayList; 021import java.util.Iterator; 022import java.util.List; 023import java.util.StringTokenizer; 024 025import org.slf4j.Logger; 026import org.slf4j.LoggerFactory; 027 028import org.eclipse.jface.dialogs.MessageDialog; 029import org.eclipse.swt.SWT; 030import org.eclipse.swt.custom.ScrolledComposite; 031import org.eclipse.swt.events.MenuAdapter; 032import org.eclipse.swt.events.MenuEvent; 033import org.eclipse.swt.events.SelectionAdapter; 034import org.eclipse.swt.events.SelectionEvent; 035import org.eclipse.swt.graphics.Font; 036import org.eclipse.swt.graphics.Point; 037import org.eclipse.swt.graphics.Rectangle; 038import org.eclipse.swt.layout.GridData; 039import org.eclipse.swt.layout.GridLayout; 040import org.eclipse.swt.widgets.Button; 041import org.eclipse.swt.widgets.Combo; 042import org.eclipse.swt.widgets.Composite; 043import org.eclipse.swt.widgets.Dialog; 044import org.eclipse.swt.widgets.Display; 045import org.eclipse.swt.widgets.Event; 046import org.eclipse.swt.widgets.FileDialog; 047import org.eclipse.swt.widgets.Label; 048import org.eclipse.swt.widgets.Listener; 049import org.eclipse.swt.widgets.Menu; 050import org.eclipse.swt.widgets.MenuItem; 051import org.eclipse.swt.widgets.Shell; 052import org.eclipse.swt.widgets.TabFolder; 053import org.eclipse.swt.widgets.TabItem; 054import org.eclipse.swt.widgets.Table; 055import org.eclipse.swt.widgets.TableColumn; 056import org.eclipse.swt.widgets.TableItem; 057import org.eclipse.swt.widgets.Text; 058 059import hdf.hdf5lib.H5; 060import hdf.hdf5lib.HDF5Constants; 061import hdf.object.Attribute; 062import hdf.object.CompoundDS; 063import hdf.object.Dataset; 064import hdf.object.Datatype; 065import hdf.object.FileFormat; 066import hdf.object.Group; 067import hdf.object.HObject; 068import hdf.object.MetaDataContainer; 069import hdf.object.ScalarDS; 070import hdf.object.h5.H5ReferenceType; 071import hdf.object.h5.H5ReferenceType.H5ReferenceData; 072 073import hdf.view.DefaultFileFilter; 074import hdf.view.Tools; 075import hdf.view.ViewProperties; 076import hdf.view.DataView.DataViewManager; 077import hdf.view.TreeView.DefaultTreeView; 078import hdf.view.TreeView.TreeView; 079import hdf.view.dialog.InputDialog; 080import hdf.view.dialog.NewStringAttributeDialog; 081import hdf.view.dialog.NewDataObjectDialog; 082import hdf.view.dialog.NewScalarAttributeDialog; 083//import hdf.view.dialog.NewCompoundAttributeDialog; 084 085/** 086 * DefaultBaseMetaDataView is a default implementation of the MetaDataView which 087 * is used to show data properties of an object. Data properties include 088 * attributes and general object information such as the object type, data type 089 * and data space. 090 * 091 * This base class is responsible for displaying an object's general information 092 * and attributes, since these are not object-specific. Subclasses of this class 093 * are responsible for displaying any extra object-specific content by 094 * overriding the addObjectSpecificContent() method. 095 * 096 * @author Jordan T. Henderson 097 * @version 1.0 4/20/2018 098 */ 099public abstract class DefaultBaseMetaDataView implements MetaDataView { 100 101 private static final Logger log = LoggerFactory.getLogger(DefaultBaseMetaDataView.class); 102 103 /** The default display */ 104 protected final Display display = Display.getDefault(); 105 106 /** The view manger reference */ 107 protected final DataViewManager viewManager; 108 109 private final Composite parent; 110 111 /** The metadata container */ 112 protected final TabFolder contentTabFolder; 113 114 /** The attribute metadata pane */ 115 protected final Composite attributeInfoPane; 116 117 /** The general metadata pane */ 118 protected final Composite generalObjectInfoPane; 119 120 /** The current font */ 121 protected Font curFont; 122 123 /** The HDF data object */ 124 protected HObject dataObject; 125 126 /* The table to hold the list of attributes attached to the HDF object */ 127 private Table attrTable; 128 129 private Label attrNumberLabel; 130 131 private List<?> attrList; 132 133 private int numAttributes; 134 135 /** The HDF data object is hdf5 type */ 136 protected boolean isH5; 137 /** The HDF data object is hdf4 type */ 138 protected boolean isH4; 139 /** The HDF data object is netcdf type */ 140 protected boolean isN3; 141 142 private static final String[] attrTableColNames = { "Name", "Type", "Array Size", "Value[50](...)" }; 143 144 private static final int ATTR_TAB_INDEX = 0; 145 private static final int GENERAL_TAB_INDEX = 1; 146 147 /** 148 *The metadata view interface for displaying metadata information 149 * 150 * @param parentComposite 151 * the parent visual object 152 * @param viewer 153 * the viewer to use 154 * @param theObj 155 * the object to display the metadata info 156 */ 157 public DefaultBaseMetaDataView(Composite parentComposite, DataViewManager viewer, HObject theObj) { 158 this.parent = parentComposite; 159 this.viewManager = viewer; 160 this.dataObject = theObj; 161 162 numAttributes = 0; 163 164 isH5 = dataObject.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5)); 165 isH4 = dataObject.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4)); 166 isN3 = dataObject.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_NC3)); 167 168 try { 169 curFont = new Font(display, ViewProperties.getFontType(), ViewProperties.getFontSize(), SWT.NORMAL); 170 } 171 catch (Exception ex) { 172 curFont = null; 173 } 174 175 /* Get the metadata information before adding GUI components */ 176 try { 177 attrList = ((MetaDataContainer) dataObject).getMetadata(); 178 if (attrList != null) 179 numAttributes = attrList.size(); 180 } 181 catch (Exception ex) { 182 attrList = null; 183 log.debug("Error retrieving metadata of object '" + dataObject.getName() + "':", ex); 184 } 185 for (int i = 0; i < numAttributes; i++) { 186 Attribute attr = (Attribute) attrList.get(i); 187 Datatype atype = attr.getAttributeDatatype(); 188 if (isH5 && atype.isRef()) { 189 H5ReferenceType rtype = (H5ReferenceType)atype; 190 try { 191 List<H5ReferenceData> refdata = (List)rtype.getData(); 192 for (int r = 0; r < (int)rtype.getRefSize(); r++) { 193 H5ReferenceData rf = refdata.get(r); 194 log.trace("constructor: refdata {}", rf.ref_array); 195 } 196 } 197 catch (Exception ex) { 198 log.trace("Error retrieving H5ReferenceData of object ", ex); 199 } 200 } 201 } 202 203 log.trace("dataObject={} isN3={} isH4={} isH5={} numAttributes={}", dataObject, isN3, isH4, isH5, numAttributes); 204 205 contentTabFolder = new TabFolder(parent, SWT.NONE); 206 contentTabFolder.addSelectionListener(new SelectionAdapter() { 207 @Override 208 public void widgetSelected(SelectionEvent e) { 209 switch (contentTabFolder.getSelectionIndex()) { 210 case ATTR_TAB_INDEX: 211 parent.setData("MetaDataView.LastTabIndex", ATTR_TAB_INDEX); 212 break; 213 case GENERAL_TAB_INDEX: 214 default: 215 parent.setData("MetaDataView.LastTabIndex", GENERAL_TAB_INDEX); 216 break; 217 } 218 } 219 }); 220 221 attributeInfoPane = createAttributeInfoPane(contentTabFolder, dataObject); 222 if (attributeInfoPane != null) { 223 TabItem attributeInfoItem = new TabItem(contentTabFolder, SWT.None, ATTR_TAB_INDEX); 224 attributeInfoItem.setText("Object Attribute Info"); 225 attributeInfoItem.setControl(attributeInfoPane); 226 } 227 228 generalObjectInfoPane = createGeneralObjectInfoPane(contentTabFolder, dataObject); 229 if (generalObjectInfoPane != null) { 230 TabItem generalInfoItem = new TabItem(contentTabFolder, SWT.None, GENERAL_TAB_INDEX); 231 generalInfoItem.setText("General Object Info"); 232 generalInfoItem.setControl(generalObjectInfoPane); 233 } 234 235 /* Add any extra information depending on the object type */ 236 try { 237 addObjectSpecificContent(); 238 } 239 catch (UnsupportedOperationException ex) { 240 } 241 242 if (parent instanceof ScrolledComposite) 243 ((ScrolledComposite) parent).setContent(contentTabFolder); 244 245 /* 246 * If the MetaDataView.LastTabIndex key data exists in the parent 247 * composite, retrieve its value to determine which remembered 248 * tab to select. 249 */ 250 Object lastTabObject = parent.getData("MetaDataView.LastTabIndex"); 251 if (lastTabObject != null) { 252 contentTabFolder.setSelection((int) lastTabObject); 253 } 254 } 255 256 /** 257 * Additional metadata to display 258 */ 259 protected abstract void addObjectSpecificContent(); 260 261 private Composite createAttributeInfoPane(Composite parent, final HObject dataObject) { 262 if (parent == null || dataObject == null) return null; 263 264 org.eclipse.swt.widgets.Group attributeInfoGroup = null; 265 266 attributeInfoGroup = new org.eclipse.swt.widgets.Group(parent, SWT.NONE); 267 attributeInfoGroup.setFont(curFont); 268 attributeInfoGroup.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW)); 269 attributeInfoGroup.setLayout(new GridLayout(3, false)); 270 attributeInfoGroup.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 271 272 if (isH5) { 273 StringBuilder objCreationStr = new StringBuilder("Creation Order NOT Tracked"); 274 long ocplID = -1; 275 long objid = -1; 276 int creationOrder = 0; 277 try { 278 objid = dataObject.open(); 279 if (objid >= 0) { 280 if (dataObject instanceof Group) { 281 ocplID = H5.H5Gget_create_plist(objid); 282 } 283 else if (dataObject instanceof Dataset) { 284 ocplID = H5.H5Dget_create_plist(objid); 285 } 286 if (ocplID >= 0) { 287 creationOrder = H5.H5Pget_attr_creation_order(ocplID); 288 log.trace("createAttributeInfoPane(): creationOrder={}", creationOrder); 289 if ((creationOrder & HDF5Constants.H5P_CRT_ORDER_TRACKED) > 0) { 290 objCreationStr.setLength(0); 291 objCreationStr.append("Creation Order Tracked"); 292 if ((creationOrder & HDF5Constants.H5P_CRT_ORDER_INDEXED) > 0) 293 objCreationStr.append(" and Indexed"); 294 } 295 } 296 } 297 } 298 finally { 299 H5.H5Pclose(ocplID); 300 dataObject.close(objid); 301 } 302 303 /* Creation order section */ 304 Label label; 305 label = new Label(attributeInfoGroup, SWT.LEFT); 306 label.setFont(curFont); 307 label.setText("Attribute Creation Order: "); 308 label.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, false, false)); 309 310 Text text; 311 text = new Text(attributeInfoGroup, SWT.SINGLE | SWT.BORDER); 312 text.setEditable(false); 313 text.setFont(curFont); 314 text.setText(objCreationStr.toString()); 315 text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1)); 316 } 317 318 log.trace("createAttributeInfoPane(): numAttributes={}", numAttributes); 319 320 attrNumberLabel = new Label(attributeInfoGroup, SWT.RIGHT); 321 attrNumberLabel.setFont(curFont); 322 attrNumberLabel.setText("Number of attributes = 0"); 323 attrNumberLabel.setLayoutData(new GridData(SWT.BEGINNING, SWT.FILL, false, false)); 324 325 Button addButton = new Button(attributeInfoGroup, SWT.PUSH); 326 addButton.setFont(curFont); 327 addButton.setText("Add Attribute"); 328 addButton.setEnabled(!(dataObject.getFileFormat().isReadOnly())); 329 addButton.setLayoutData(new GridData(SWT.END, SWT.FILL, true, false)); 330 addButton.addSelectionListener(new SelectionAdapter() { 331 @Override 332 public void widgetSelected(SelectionEvent e) { 333 addAttribute(dataObject); 334 } 335 }); 336 337 /* Deleting attributes is not supported by HDF4 */ 338 Button delButton = new Button(attributeInfoGroup, SWT.PUSH); 339 delButton.setFont(curFont); 340 delButton.setText("Delete Attribute"); 341 delButton.setEnabled(isH5 && !(dataObject.getFileFormat().isReadOnly())); 342 delButton.setLayoutData(new GridData(SWT.END, SWT.FILL, false, false)); 343 delButton.addSelectionListener(new SelectionAdapter() { 344 @Override 345 public void widgetSelected(SelectionEvent e) { 346 deleteAttribute(dataObject); 347 } 348 }); 349 350 attrTable = new Table(attributeInfoGroup, SWT.FULL_SELECTION | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL); 351 attrTable.setLinesVisible(true); 352 attrTable.setHeaderVisible(true); 353 attrTable.setFont(curFont); 354 attrTable.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1)); 355 356 Menu attrPopupMenu = createAttributePopupMenu(attrTable); 357 attrTable.setMenu(attrPopupMenu); 358 359 /* 360 * Add a double-click listener for editing attribute values in a separate 361 * TableView 362 */ 363 attrTable.addListener(SWT.MouseDoubleClick, new Listener() { 364 @Override 365 public void handleEvent(Event arg0) { 366 int selectionIndex = attrTable.getSelectionIndex(); 367 if (selectionIndex < 0) { 368 Tools.showError(Display.getDefault().getShells()[0], "Select", "No Attribute selected"); 369 return; 370 } 371 372 final TableItem item = attrTable.getItem(selectionIndex); 373 374 viewManager.getTreeView().setDefaultDisplayMode(true); 375 376 try { 377 Display.getDefault().syncExec(new Runnable() { 378 @Override 379 public void run() { 380 try { 381 HObject selectedObject = (HObject) item.getData(); 382 if ((selectedObject instanceof Dataset) && !((Dataset) selectedObject).isNULL()) { 383 viewManager.getTreeView().showDataContent(selectedObject); 384 } 385 else { 386 Tools.showInformation(Display.getDefault().getShells()[0], "Open", 387 "No data to display in an object with a NULL dataspace."); 388 } 389 } 390 catch (Exception ex) { 391 log.debug("Attribute showDataContent failure: ", ex); 392 } 393 } 394 }); 395 } 396 catch (Exception e) { 397 log.debug("Attribute showDataContent loading manually interrupted"); 398 } 399 } 400 }); 401 402 /* 403 * Add a right-click listener for showing a menu that has options for renaming 404 * an attribute, editing an attribute, or deleting an attribute 405 */ 406 attrTable.addListener(SWT.MenuDetect, new Listener() { 407 @Override 408 public void handleEvent(Event arg0) { 409 int index = attrTable.getSelectionIndex(); 410 if (index < 0) return; 411 412 attrTable.getMenu().setVisible(true); 413 } 414 }); 415 416 for (int i = 0; i < attrTableColNames.length; i++) { 417 TableColumn column = new TableColumn(attrTable, SWT.NONE); 418 column.setText(attrTableColNames[i]); 419 column.setMoveable(false); 420 421 /* 422 * Make sure all columns show even when the object in question has no attributes 423 */ 424 if (i == attrTableColNames.length - 1) 425 column.setWidth(200); 426 else 427 column.setWidth(50); 428 } 429 430 if (attrList != null) { 431 attrNumberLabel.setText("Number of attributes = " + numAttributes); 432 433 Attribute attr = null; 434 for (int i = 0; i < numAttributes; i++) { 435 attr = (Attribute) attrList.get(i); 436 437 log.trace("createAttributeInfoPane(): attr[{}] is {} of type {}", i, attr.getAttributeName(), 438 attr.getAttributeDatatype().getDescription()); 439 440 addAttributeTableItem(attrTable, attr); 441 } 442 } 443 444 for (int i = 0; i < attrTableColNames.length; i++) { 445 attrTable.getColumn(i).pack(); 446 } 447 448 // Prevent attributes with many values, such as array types, from making 449 // the window too wide 450 attrTable.getColumn(3).setWidth(200); 451 452 return attributeInfoGroup; 453 } 454 455 private Composite createGeneralObjectInfoPane(Composite parent, final HObject dataObject) { 456 if (parent == null || dataObject == null) return null; 457 458 FileFormat theFile = dataObject.getFileFormat(); 459 boolean isRoot = ((dataObject instanceof Group) && ((Group) dataObject).isRoot()); 460 String objTypeStr = "Unknown"; 461 Label label; 462 Text text; 463 464 /* Add an SWT Group to encompass all of the GUI components */ 465 org.eclipse.swt.widgets.Group generalInfoGroup = new org.eclipse.swt.widgets.Group(parent, SWT.NONE); 466 generalInfoGroup.setFont(curFont); 467 generalInfoGroup.setLayout(new GridLayout(2, false)); 468 generalInfoGroup.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_LIGHT_SHADOW)); 469 470 /* Object name section */ 471 label = new Label(generalInfoGroup, SWT.LEFT); 472 label.setFont(curFont); 473 label.setText("Name: "); 474 475 text = new Text(generalInfoGroup, SWT.SINGLE | SWT.BORDER); 476 text.setEditable(false); 477 text.setFont(curFont); 478 text.setText(dataObject.getName()); 479 text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 480 481 /* Object Path section */ 482 label = new Label(generalInfoGroup, SWT.LEFT); 483 label.setFont(curFont); 484 label.setText("Path: "); 485 486 text = new Text(generalInfoGroup, SWT.SINGLE | SWT.BORDER); 487 text.setEditable(false); 488 text.setFont(curFont); 489 text.setText(dataObject.getPath() == null ? "/" 490 : dataObject.getPath()); /* TODO: temporary workaround until Object Library is fixed */ 491 text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 492 493 /* Object Type section */ 494 label = new Label(generalInfoGroup, SWT.LEFT); 495 label.setFont(curFont); 496 label.setText("Type: "); 497 498 if (isH5) { 499 if (dataObject instanceof Group) { 500 objTypeStr = "HDF5 Group"; 501 } 502 else if (dataObject instanceof ScalarDS) { 503 objTypeStr = "HDF5 Dataset"; 504 } 505 else if (dataObject instanceof CompoundDS) { 506 objTypeStr = "HDF5 Dataset"; 507 } 508 else if (dataObject instanceof Datatype) { 509 objTypeStr = "HDF5 Named Datatype"; 510 } 511 else { 512 log.debug("createGeneralObjectInfoPane(): unknown HDF5 dataObject"); 513 } 514 } 515 else if (isH4) { 516 if (dataObject instanceof Group) { 517 objTypeStr = "HDF4 Group"; 518 } 519 else if (dataObject instanceof ScalarDS) { 520 ScalarDS ds = (ScalarDS) dataObject; 521 if (ds.isImage()) { 522 objTypeStr = "HDF4 Raster Image"; 523 } 524 else { 525 objTypeStr = "HDF4 SDS"; 526 } 527 } 528 else if (dataObject instanceof CompoundDS) { 529 objTypeStr = "HDF4 Vdata"; 530 } 531 else { 532 log.debug("createGeneralObjectInfoPane(): unknown HDF4 dataObject"); 533 } 534 } 535 else if (isN3) { 536 if (dataObject instanceof Group) { 537 objTypeStr = "netCDF3 Group"; 538 } 539 else if (dataObject instanceof ScalarDS) { 540 objTypeStr = "netCDF3 Dataset"; 541 } 542 else { 543 log.debug("createGeneralObjectInfoPane(): unknown netCDF3 dataObject"); 544 } 545 } 546 else { 547 if (dataObject instanceof Group) { 548 objTypeStr = "Group"; 549 } 550 else if (dataObject instanceof ScalarDS) { 551 objTypeStr = "Dataset"; 552 } 553 else if (dataObject instanceof CompoundDS) { 554 objTypeStr = "Dataset"; 555 } 556 else { 557 log.debug("createGeneralObjectInfoPane(): unknown dataObject"); 558 } 559 } 560 561 text = new Text(generalInfoGroup, SWT.SINGLE | SWT.BORDER); 562 text.setEditable(false); 563 text.setFont(curFont); 564 text.setText(objTypeStr); 565 text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 566 567 /* Object ID section */ 568 569 // bug #926 to remove the OID, put it back on Nov. 20, 2008, --PC 570 String oidStr = null; 571 long[] oID = dataObject.getOID(); 572 if (oID != null) { 573 oidStr = String.valueOf(oID[0]); 574 if (isH4) 575 oidStr += ", " + oID[1]; 576 577 if (isH5) { 578 label = new Label(generalInfoGroup, SWT.LEFT); 579 label.setFont(curFont); 580 label.setText("Object Ref: "); 581 } 582 else { 583 label = new Label(generalInfoGroup, SWT.LEFT); 584 label.setFont(curFont); 585 label.setText("Tag, Ref: "); 586 } 587 588 text = new Text(generalInfoGroup, SWT.SINGLE | SWT.BORDER); 589 text.setEditable(false); 590 text.setFont(curFont); 591 text.setText(oidStr); 592 text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 593 } 594 595 /* 596 * If this is the root group, add some special extra info, such as the Library 597 * Version bounds set for the file. 598 */ 599 if (isRoot) { 600 /* Get the file's size */ 601 long fileSize = 0; 602 try { 603 fileSize = (new File(dataObject.getFile())).length(); 604 } 605 catch (Exception ex) { 606 fileSize = -1; 607 } 608 fileSize /= 1024; 609 610 /* Retrieve the number of subgroups and datasets in the root group */ 611 HObject root = theFile.getRootObject(); 612 HObject theObj = null; 613 Iterator<HObject> it = ((Group) root).depthFirstMemberList().iterator(); 614 int groupCount = 0; 615 int datasetCount = 0; 616 617 while (it.hasNext()) { 618 theObj = it.next(); 619 620 if (theObj instanceof Group) 621 groupCount++; 622 else 623 datasetCount++; 624 } 625 626 /* Append all of the file's information to the general object info pane */ 627 String fileInfo = ""; 628 629 fileInfo = "size=" + fileSize + "K, groups=" + groupCount + ", datasets=" + datasetCount; 630 631 /* File name section */ 632 label = new Label(generalInfoGroup, SWT.LEFT); 633 label.setFont(curFont); 634 label.setText("File Name: "); 635 636 text = new Text(generalInfoGroup, SWT.SINGLE | SWT.BORDER); 637 text.setEditable(false); 638 text.setFont(curFont); 639 text.setText(dataObject.getFileFormat().getName()); 640 text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 641 642 /* File Path section */ 643 label = new Label(generalInfoGroup, SWT.LEFT); 644 label.setFont(curFont); 645 label.setText("File Path: "); 646 647 text = new Text(generalInfoGroup, SWT.SINGLE | SWT.BORDER); 648 text.setEditable(false); 649 text.setFont(curFont); 650 text.setText((new File(dataObject.getFile())).getParent()); 651 text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 652 653 label = new Label(generalInfoGroup, SWT.LEFT); 654 label.setFont(curFont); 655 label.setText("File Type: "); 656 657 if (isH5) 658 objTypeStr = "HDF5, " + fileInfo; 659 else if (isH4) 660 objTypeStr = "HDF4, " + fileInfo; 661 else if (isN3) 662 objTypeStr = "netCDF3, " + fileInfo; 663 else 664 objTypeStr = fileInfo; 665 666 text = new Text(generalInfoGroup, SWT.SINGLE | SWT.BORDER); 667 text.setEditable(false); 668 text.setFont(curFont); 669 text.setText(objTypeStr); 670 text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 671 672 if (isH5) { 673 log.trace("createGeneralObjectInfoPane(): get Library Version bounds info"); 674 String libversion = ""; 675 try { 676 libversion = dataObject.getFileFormat().getLibBoundsDescription(); 677 } 678 catch (Exception ex) { 679 log.debug("Get Library Bounds Description failure: ", ex); 680 } 681 682 if (libversion.length() > 0) { 683 label = new Label(generalInfoGroup, SWT.LEFT); 684 label.setFont(curFont); 685 label.setText("Library version bounds: "); 686 687 text = new Text(generalInfoGroup, SWT.SINGLE | SWT.BORDER); 688 text.setEditable(false); 689 text.setFont(curFont); 690 text.setText(libversion); 691 text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 692 } 693 694 Button userBlockButton = new Button(generalInfoGroup, SWT.PUSH); 695 userBlockButton.setText("Show User Block"); 696 userBlockButton.addSelectionListener(new SelectionAdapter() { 697 @Override 698 public void widgetSelected(SelectionEvent e) { 699 new UserBlockDialog(display.getShells()[0], SWT.NONE, dataObject).open(); 700 } 701 }); 702 } 703 } 704 705 /* Add a dummy label to take up some vertical space between sections */ 706 label = new Label(generalInfoGroup, SWT.LEFT); 707 label.setText(""); 708 label.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1)); 709 710 return generalInfoGroup; 711 } 712 713 @Override 714 public HObject getDataObject() { 715 return dataObject; 716 } 717 718 private Menu createAttributePopupMenu(final Table table) { 719 final Menu menu = new Menu(table); 720 MenuItem item; 721 722 item = new MenuItem(menu, SWT.PUSH); 723 item.setText("Rename Attribute"); 724 item.addSelectionListener(new SelectionAdapter() { 725 @Override 726 public void widgetSelected(SelectionEvent e) { 727 int selectionIndex = table.getSelectionIndex(); 728 if (selectionIndex < 0) { 729 Tools.showError(Display.getDefault().getShells()[0], "Select", "No Attribute selected"); 730 return; 731 } 732 733 HObject itemObj = (HObject) table.getItem(selectionIndex).getData(); 734 String result = new InputDialog(Display.getDefault().getShells()[0], 735 Display.getDefault().getShells()[0].getText() + " - Rename Attribute", "New Attribute Name", 736 itemObj.getName()).open(); 737 738 if ((result == null) || ((result = result.trim()) == null) || (result.length() < 1)) { 739 return; 740 } 741 742 Attribute attr = (Attribute) attrTable.getItem(selectionIndex).getData(); 743 renameAttribute(attr, result); 744 } 745 }); 746 747 item = new MenuItem(menu, SWT.PUSH); 748 item.setText("View/Edit Attribute Value"); 749 item.addSelectionListener(new SelectionAdapter() { 750 @Override 751 public void widgetSelected(SelectionEvent e) { 752 int selectionIndex = attrTable.getSelectionIndex(); 753 if (selectionIndex < 0) { 754 Tools.showError(Display.getDefault().getShells()[0], "Select", "No Attribute selected"); 755 return; 756 } 757 758 final TableItem item = attrTable.getItem(selectionIndex); 759 760 viewManager.getTreeView().setDefaultDisplayMode(true); 761 762 try { 763 Display.getDefault().syncExec(new Runnable() { 764 @Override 765 public void run() { 766 try { 767 HObject selectedObject = (HObject) item.getData(); 768 if ((selectedObject instanceof Dataset) && !((Dataset) selectedObject).isNULL()) { 769 viewManager.getTreeView().showDataContent(selectedObject); 770 } 771 else { 772 Tools.showInformation(Display.getDefault().getShells()[0], "Open", 773 "No data to display in an object with a NULL dataspace."); 774 } 775 } 776 catch (Exception ex) { 777 log.debug("Attribute showDataContent failure: ", ex); 778 } 779 } 780 }); 781 } 782 catch (Exception ex) { 783 log.debug("Attribute showDataContent loading manually interrupted"); 784 } 785 } 786 }); 787 788 item = new MenuItem(menu, SWT.PUSH); 789 item.setText("Delete Attribute"); 790 item.addSelectionListener(new SelectionAdapter() { 791 @Override 792 public void widgetSelected(SelectionEvent e) { 793 int selectionIndex = attrTable.getSelectionIndex(); 794 if (selectionIndex < 0) { 795 Tools.showError(Display.getDefault().getShells()[0], "Select", "No Attribute selected"); 796 return; 797 } 798 799 deleteAttribute(dataObject); 800 } 801 }); 802 803 menu.addMenuListener(new MenuAdapter() { 804 @Override 805 public void menuShown(MenuEvent e) { 806 /* 'Rename Attribute' MenuItem */ 807 menu.getItem(0).setEnabled(!dataObject.getFileFormat().isReadOnly() && !isH4); 808 809 /* 'Delete Attribute' MenuItem */ 810 menu.getItem(2).setEnabled(!dataObject.getFileFormat().isReadOnly() && !isH4); 811 } 812 }); 813 814 return menu; 815 } 816 817 @Override 818 public Attribute addAttribute(HObject obj) { 819 if (obj == null) return null; 820 821 HObject root = obj.getFileFormat().getRootObject(); 822 Attribute attr = null; 823 if (isH5) { 824 NewScalarAttributeDialog dialog = new NewScalarAttributeDialog(display.getShells()[0], obj, 825 ((Group) root).breadthFirstMemberList()); 826 dialog.open(); 827 attr = dialog.getAttribute(); 828 } 829 else { 830 NewStringAttributeDialog dialog = new NewStringAttributeDialog(display.getShells()[0], obj, 831 ((Group) root).breadthFirstMemberList()); 832 dialog.open(); 833 attr = dialog.getAttribute(); 834 } 835 836 if (attr == null) { 837 log.debug("addAttribute(): attr is null"); 838 return null; 839 } 840 841 addAttributeTableItem(attrTable, attr); 842 843 numAttributes++; 844 attrNumberLabel.setText("Number of attributes = " + numAttributes); 845 846 if (viewManager.getTreeView() instanceof DefaultTreeView) 847 ((DefaultTreeView) viewManager.getTreeView()).updateItemIcon(obj); 848 849 return attr; 850 } 851 852 @Override 853 public Attribute deleteAttribute(HObject obj) { 854 if (obj == null) return null; 855 856 int idx = attrTable.getSelectionIndex(); 857 if (idx < 0) { 858 log.debug("deleteAttribute(): no attribute is selected"); 859 Tools.showError(display.getShells()[0], "Delete", "No attribute is selected."); 860 return null; 861 } 862 863 int answer = SWT.NO; 864 if (Tools.showConfirm(display.getShells()[0], "Delete", 865 "Do you want to delete the selected attribute?")) 866 answer = SWT.YES; 867 if (answer == SWT.NO) { 868 log.trace("deleteAttribute(): attribute deletion cancelled"); 869 return null; 870 } 871 872 if (attrList == null) { 873 log.debug("deleteAttribute(): Attribute list was null; can't delete an attribute from it"); 874 return null; 875 } 876 877 Attribute attr = (Attribute) attrList.get(idx); 878 879 log.trace("deleteAttribute(): Attribute selected for deletion: {}", attr.getAttributeName()); 880 881 try { 882 ((MetaDataContainer) obj).removeMetadata(attr); 883 } 884 catch (Exception ex) { 885 log.debug("deleteAttribute(): attribute deletion failed for object '{}': ", obj.getName(), ex); 886 } 887 888 attrTable.remove(idx); 889 numAttributes--; 890 891 attrNumberLabel.setText("Number of attributes = " + numAttributes); 892 893 if (viewManager.getTreeView() instanceof DefaultTreeView) 894 ((DefaultTreeView) viewManager.getTreeView()).updateItemIcon(obj); 895 896 return attr; 897 } 898 899 private void renameAttribute(Attribute attr, String newName) { 900 if ((attr == null) || (newName == null) || (newName = newName.trim()) == null || (newName.length() < 1)) { 901 log.debug("renameAttribute(): Attribute is null or Attribute's new name is null"); 902 return; 903 } 904 905 String attrName = attr.getAttributeName(); 906 907 log.trace("renameAttribute(): oldName={} newName={}", attrName, newName); 908 909 if (isH5) { 910 try { 911 dataObject.getFileFormat().renameAttribute(dataObject, attrName, newName); 912 } 913 catch (Exception ex) { 914 log.debug("renameAttribute(): renaming failure:", ex); 915 Tools.showError(display.getShells()[0], "Delete", ex.getMessage()); 916 } 917 918 /* Update the attribute table */ 919 int selectionIndex = attrTable.getSelectionIndex(); 920 if (selectionIndex < 0) { 921 Tools.showError(Display.getDefault().getShells()[0], "Delete", "No Attribute selected"); 922 return; 923 } 924 925 attrTable.getItem(selectionIndex).setText(0, newName); 926 } 927 else { 928 log.debug("renameAttribute(): renaming attributes is only allowed for HDF5 files"); 929 } 930 931 if (dataObject instanceof MetaDataContainer) { 932 try { 933 ((MetaDataContainer) dataObject).updateMetadata(attr); 934 } 935 catch (Exception ex) { 936 log.debug("renameAttribute(): updateMetadata() failure:", ex); 937 Tools.showError(display.getShells()[0], "Delete", ex.getMessage()); 938 } 939 } 940 } 941 942 /** 943 * Update an attribute's value. Currently can only update a single data point. 944 * 945 * @param attr 946 * the selected attribute. 947 * @param newValue 948 * the string of the new value. 949 */ 950 private void updateAttributeValue(Attribute attr, String newValue) { 951 if ((attr == null) || (newValue == null) || (newValue = newValue.trim()) == null || (newValue.length() < 1)) { 952 log.debug("updateAttributeValue(): Attribute is null or Attribute's new value is null"); 953 return; 954 } 955 956 String attrName = attr.getAttributeName(); 957 Object data; 958 959 log.trace("updateAttributeValue(): changing value of attribute '{}'", attrName); 960 961 try { 962 data = attr.getAttributeData(); 963 } 964 catch (Exception ex) { 965 log.debug("updateAttributeValue(): getData() failure:", ex); 966 return; 967 } 968 969 if (data == null) { 970 log.debug("updateAttributeValue(): attribute's data was null"); 971 return; 972 } 973 974 int arrayLength = Array.getLength(data); 975 StringTokenizer st = new StringTokenizer(newValue, ","); 976 if (st.countTokens() < arrayLength) { 977 log.debug("updateAttributeValue(): More data values needed: {}", newValue); 978 Tools.showError(display.getShells()[0], "Update", "More data values needed: " + newValue); 979 return; 980 } 981 982 char cNT = ' '; 983 String cName = data.getClass().getName(); 984 int cIndex = cName.lastIndexOf('['); 985 if (cIndex >= 0) { 986 cNT = cName.charAt(cIndex + 1); 987 } 988 boolean isUnsigned = attr.getAttributeDatatype().isUnsigned(); 989 990 log.trace("updateAttributeValue(): array_length={} cName={} NT={} isUnsigned={}", arrayLength, cName, 991 cNT, isUnsigned); 992 993 double d = 0; 994 String theToken = null; 995 long max = 0; 996 long min = 0; 997 for (int i = 0; i < arrayLength; i++) { 998 max = min = 0; 999 theToken = st.nextToken().trim(); 1000 try { 1001 if (!(Array.get(data, i) instanceof String)) { 1002 d = Double.parseDouble(theToken); 1003 } 1004 } 1005 catch (NumberFormatException ex) { 1006 log.debug("updateAttributeValue(): NumberFormatException: ", ex); 1007 Tools.showError(display.getShells()[0], "Update", ex.getMessage()); 1008 return; 1009 } 1010 1011 if (isUnsigned && (d < 0)) { 1012 log.debug("updateAttributeValue(): Negative value for unsigned integer: {}", theToken); 1013 Tools.showError(display.getShells()[0], "Update", "Negative value for unsigned integer: " + theToken); 1014 return; 1015 } 1016 1017 switch (cNT) { 1018 case 'B': { 1019 if (isUnsigned) { 1020 min = 0; 1021 max = 255; 1022 } 1023 else { 1024 min = Byte.MIN_VALUE; 1025 max = Byte.MAX_VALUE; 1026 } 1027 1028 if ((d > max) || (d < min)) { 1029 Tools.showError(display.getShells()[0], "Update", 1030 "Data is out of range[" + min + ", " + max + "]: " + theToken); 1031 } 1032 else { 1033 Array.setByte(data, i, (byte) d); 1034 } 1035 break; 1036 } 1037 case 'S': { 1038 if (isUnsigned) { 1039 min = 0; 1040 max = 65535; 1041 } 1042 else { 1043 min = Short.MIN_VALUE; 1044 max = Short.MAX_VALUE; 1045 } 1046 1047 if ((d > max) || (d < min)) { 1048 Tools.showError(display.getShells()[0], "Update", 1049 "Data is out of range[" + min + ", " + max + "]: " + theToken); 1050 } 1051 else { 1052 Array.setShort(data, i, (short) d); 1053 } 1054 break; 1055 } 1056 case 'I': { 1057 if (isUnsigned) { 1058 min = 0; 1059 max = 4294967295L; 1060 } 1061 else { 1062 min = Integer.MIN_VALUE; 1063 max = Integer.MAX_VALUE; 1064 } 1065 1066 if ((d > max) || (d < min)) { 1067 Tools.showError(display.getShells()[0], "Update", 1068 "Data is out of range[" + min + ", " + max + "]: " + theToken); 1069 } 1070 else { 1071 Array.setInt(data, i, (int) d); 1072 } 1073 break; 1074 } 1075 case 'J': 1076 long lvalue = 0; 1077 if (isUnsigned) { 1078 if (theToken != null) { 1079 String theValue = theToken; 1080 BigInteger maxJ = new BigInteger("18446744073709551615"); 1081 BigInteger big = new BigInteger(theValue); 1082 if ((big.compareTo(maxJ) > 0) || (big.compareTo(BigInteger.ZERO) < 0)) { 1083 Tools.showError(display.getShells()[0], "Update", 1084 "Data is out of range[" + min + ", " + max + "]: " + theToken); 1085 } 1086 lvalue = big.longValue(); 1087 log.trace("updateAttributeValue(): big.longValue={}", lvalue); 1088 Array.setLong(data, i, lvalue); 1089 } 1090 else 1091 Array.set(data, i, theToken); 1092 } 1093 else { 1094 min = Long.MIN_VALUE; 1095 max = Long.MAX_VALUE; 1096 if ((d > max) || (d < min)) { 1097 Tools.showError(display.getShells()[0], "Update", 1098 "Data is out of range[" + min + ", " + max + "]: " + theToken); 1099 } 1100 lvalue = (long) d; 1101 log.trace("updateAttributeValue(): longValue={}", lvalue); 1102 Array.setLong(data, i, lvalue); 1103 } 1104 break; 1105 case 'F': 1106 Array.setFloat(data, i, (float) d); 1107 break; 1108 case 'D': 1109 Array.setDouble(data, i, d); 1110 break; 1111 default: 1112 Array.set(data, i, theToken); 1113 break; 1114 } 1115 } 1116 1117 try { 1118 dataObject.getFileFormat().writeAttribute(dataObject, attr, true); 1119 } 1120 catch (Exception ex) { 1121 log.debug("updateAttributeValue(): writeAttribute failure: ", ex); 1122 Tools.showError(display.getShells()[0], "Update", ex.getMessage()); 1123 return; 1124 } 1125 1126 /* Update the attribute table */ 1127 int selectionIndex = attrTable.getSelectionIndex(); 1128 if (selectionIndex < 0) { 1129 Tools.showError(Display.getDefault().getShells()[0], "Update", "No Attribute selected"); 1130 return; 1131 } 1132 1133 attrTable.getItem(selectionIndex).setText(3, attr.toAttributeString(", ")); 1134 1135 if (dataObject instanceof MetaDataContainer) { 1136 try { 1137 ((MetaDataContainer) dataObject).updateMetadata(attr); 1138 } 1139 catch (Exception ex) { 1140 log.debug("updateAttributeValue(): updateMetadata() failure:", ex); 1141 Tools.showError(display.getShells()[0], "Update", ex.getMessage()); 1142 } 1143 } 1144 } 1145 1146 private void addAttributeTableItem(Table table, Attribute attr) { 1147 if (table == null || attr == null) { 1148 log.debug("addAttributeTableItem(): table or attribute is null"); 1149 return; 1150 } 1151 1152 String attrName = attr.getAttributeName(); 1153 String attrType = attr.getAttributeDatatype().getDescription(); 1154 StringBuilder attrSize = new StringBuilder(); 1155 String attrValue = attr.toAttributeString(", ", 50); 1156 String[] rowData = new String[attrTableColNames.length]; 1157 1158 if (attrName == null) attrName = "null"; 1159 if (attrType == null) attrType = "null"; 1160 if (attrValue == null) attrValue = "null"; 1161 1162 TableItem item = new TableItem(attrTable, SWT.NONE); 1163 item.setFont(curFont); 1164 item.setData(attr); 1165 1166 if (attr.getProperty("field") != null) { 1167 rowData[0] = attrName + " {Field: " + attr.getProperty("field") + "}"; 1168 } 1169 else { 1170 rowData[0] = attrName; 1171 } 1172 1173 if (attr.isAttributeNULL()) { 1174 attrSize.append("NULL"); 1175 } 1176 else if (attr.isAttributeScalar()) { 1177 attrSize.append("Scalar"); 1178 } 1179 else { 1180 long[] dims = attr.getAttributeDims(); 1181 attrSize.append(String.valueOf(dims[0])); 1182 for (int j = 1; j < dims.length; j++) { 1183 attrSize.append(" x ").append(dims[j]); 1184 } 1185 } 1186 1187 rowData[1] = attrType; 1188 rowData[2] = attrSize.toString(); 1189 if (attr.isAttributeNULL()) 1190 rowData[3] = "NULL"; 1191 else 1192 rowData[3] = attrValue; 1193 1194 item.setText(rowData); 1195 } 1196 1197 /** 1198 * Updates the current font. 1199 * 1200 * @param font the new font 1201 */ 1202 public void updateFont(Font font) { 1203 if (curFont != null) 1204 curFont.dispose(); 1205 1206 log.trace("updateFont():"); 1207 curFont = font; 1208 1209 attributeInfoPane.setFont(font); 1210 attributeInfoPane.pack(); 1211 attributeInfoPane.requestLayout(); 1212 1213 generalObjectInfoPane.setFont(font); 1214 generalObjectInfoPane.pack(); 1215 generalObjectInfoPane.requestLayout(); 1216 } 1217 1218 private class UserBlockDialog extends Dialog { 1219 private Shell shell; 1220 1221 private final HObject obj; 1222 1223 private byte[] userBlock; 1224 1225 private final String[] displayChoices = { "Text", "Binary", "Octal", "Hexadecimal", "Decimal" }; 1226 1227 private Button jamButton; 1228 private Text userBlockArea; 1229 1230 public UserBlockDialog(Shell parent, int style, HObject obj) { 1231 super(parent, style); 1232 1233 this.obj = obj; 1234 1235 userBlock = Tools.getHDF5UserBlock(obj.getFile()); 1236 } 1237 1238 public void open() { 1239 Shell openParent = getParent(); 1240 shell = new Shell(openParent, SWT.DIALOG_TRIM | SWT.RESIZE); 1241 shell.setFont(curFont); 1242 shell.setText("User Block - " + obj); 1243 shell.setLayout(new GridLayout(5, false)); 1244 1245 Label label = new Label(shell, SWT.RIGHT); 1246 label.setFont(curFont); 1247 label.setText("Display As: "); 1248 1249 Combo userBlockDisplayChoice = new Combo(shell, SWT.SINGLE | SWT.READ_ONLY); 1250 userBlockDisplayChoice.setFont(curFont); 1251 userBlockDisplayChoice.setItems(displayChoices); 1252 userBlockDisplayChoice.select(0); 1253 userBlockDisplayChoice.addSelectionListener(new SelectionAdapter() { 1254 @Override 1255 public void widgetSelected(SelectionEvent e) { 1256 Combo source = (Combo) e.widget; 1257 int type = 0; 1258 1259 String typeName = source.getItem(source.getSelectionIndex()); 1260 1261 jamButton.setEnabled(false); 1262 userBlockArea.setEditable(false); 1263 1264 if (typeName.equalsIgnoreCase("Text")) { 1265 type = 0; 1266 jamButton.setEnabled(true); 1267 userBlockArea.setEditable(true); 1268 } 1269 else if (typeName.equalsIgnoreCase("Binary")) { 1270 type = 2; 1271 } 1272 else if (typeName.equalsIgnoreCase("Octal")) { 1273 type = 8; 1274 } 1275 else if (typeName.equalsIgnoreCase("Hexadecimal")) { 1276 type = 16; 1277 } 1278 else if (typeName.equalsIgnoreCase("Decimal")) { 1279 type = 10; 1280 } 1281 1282 showUserBlockAs(type); 1283 } 1284 }); 1285 1286 Label dummyLabel = new Label(shell, SWT.RIGHT); 1287 dummyLabel.setFont(curFont); 1288 dummyLabel.setText(""); 1289 dummyLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); 1290 1291 Label sizeLabel = new Label(shell, SWT.RIGHT); 1292 sizeLabel.setFont(curFont); 1293 sizeLabel.setText("Header Size (Bytes): 0"); 1294 1295 jamButton = new Button(shell, SWT.PUSH); 1296 jamButton.setFont(curFont); 1297 jamButton.setText("Save User Block"); 1298 jamButton.setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); 1299 jamButton.addSelectionListener(new SelectionAdapter() { 1300 @Override 1301 public void widgetSelected(SelectionEvent e) { 1302 writeUserBlock(); 1303 } 1304 }); 1305 1306 ScrolledComposite userBlockScroller = new ScrolledComposite(shell, SWT.V_SCROLL | SWT.BORDER); 1307 userBlockScroller.setExpandHorizontal(true); 1308 userBlockScroller.setExpandVertical(true); 1309 userBlockScroller.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 5, 1)); 1310 1311 userBlockArea = new Text(userBlockScroller, SWT.MULTI | SWT.WRAP); 1312 userBlockArea.setEditable(true); 1313 userBlockArea.setFont(curFont); 1314 userBlockScroller.setContent(userBlockArea); 1315 1316 Button closeButton = new Button(shell, SWT.CENTER); 1317 closeButton.setFont(curFont); 1318 closeButton.setText(" &Close "); 1319 closeButton.setLayoutData(new GridData(SWT.CENTER, SWT.FILL, true, false, 5, 1)); 1320 closeButton.addSelectionListener(new SelectionAdapter() { 1321 @Override 1322 public void widgetSelected(SelectionEvent e) { 1323 shell.dispose(); 1324 } 1325 }); 1326 1327 if (userBlock != null) { 1328 int headSize = showUserBlockAs(0); 1329 sizeLabel.setText("Header Size (Bytes): " + headSize); 1330 } 1331 else { 1332 userBlockDisplayChoice.setEnabled(false); 1333 } 1334 1335 shell.pack(); 1336 1337 Rectangle parentBounds = openParent.getBounds(); 1338 1339 Point shellSize = new Point((int) (0.5 * parentBounds.width), (int) (0.5 * parentBounds.height)); 1340 shell.setSize(shellSize); 1341 1342 shell.setLocation((parentBounds.x + (parentBounds.width / 2)) - (shellSize.x / 2), 1343 (parentBounds.y + (parentBounds.height / 2)) - (shellSize.y / 2)); 1344 1345 shell.open(); 1346 1347 Display openDisplay = openParent.getDisplay(); 1348 while (!shell.isDisposed()) { 1349 if (!openDisplay.readAndDispatch()) openDisplay.sleep(); 1350 } 1351 } 1352 1353 private int showUserBlockAs(int radix) { 1354 if (userBlock == null) return 0; 1355 1356 int headerSize = 0; 1357 1358 String userBlockInfo = null; 1359 if ((radix == 2) || (radix == 8) || (radix == 16) || (radix == 10)) { 1360 StringBuilder sb = new StringBuilder(); 1361 for (headerSize = 0; headerSize < userBlock.length; headerSize++) { 1362 int intValue = userBlock[headerSize]; 1363 if (intValue < 0) { 1364 intValue += 256; 1365 } 1366 else if (intValue == 0) { 1367 break; // null end 1368 } 1369 1370 sb.append(Integer.toString(intValue, radix)).append(" "); 1371 } 1372 userBlockInfo = sb.toString(); 1373 } 1374 else { 1375 userBlockInfo = new String(userBlock).trim(); 1376 if (userBlockInfo != null) { 1377 headerSize = userBlockInfo.length(); 1378 } 1379 } 1380 1381 userBlockArea.setText(userBlockInfo); 1382 1383 return headerSize; 1384 } 1385 1386 private void writeUserBlock() { 1387 if (!obj.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5))) { 1388 return; 1389 } 1390 1391 int blkSize0 = 0; 1392 if (userBlock != null) { 1393 blkSize0 = userBlock.length; 1394 // The super block space is allocated by offset 0, 512, 1024, 2048, etc 1395 if (blkSize0 > 0) { 1396 int offset = 512; 1397 while (offset < blkSize0) { 1398 offset *= 2; 1399 } 1400 blkSize0 = offset; 1401 } 1402 } 1403 1404 int blkSize1 = 0; 1405 String userBlockStr = userBlockArea.getText(); 1406 if (userBlockStr == null) { 1407 if (blkSize0 <= 0) { 1408 return; // nothing to write 1409 } 1410 else { 1411 userBlockStr = " "; // want to wipe out old userblock content 1412 } 1413 } 1414 byte[] buf = null; 1415 buf = userBlockStr.getBytes(); 1416 1417 blkSize1 = buf.length; 1418 if (blkSize1 <= blkSize0) { 1419 java.io.RandomAccessFile raf = null; 1420 try { 1421 raf = new java.io.RandomAccessFile(obj.getFile(), "rw"); 1422 } 1423 catch (Exception ex) { 1424 Tools.showError(shell, "Save", "Can't open output file: " + obj.getFile()); 1425 return; 1426 } 1427 1428 try { 1429 raf.seek(0); 1430 raf.write(buf, 0, buf.length); 1431 raf.seek(buf.length); 1432 if (blkSize0 > buf.length) { 1433 byte[] padBuf = new byte[blkSize0 - buf.length]; 1434 raf.write(padBuf, 0, padBuf.length); 1435 } 1436 } 1437 catch (Exception ex) { 1438 log.debug("raf write:", ex); 1439 } 1440 try { 1441 raf.close(); 1442 } 1443 catch (Exception ex) { 1444 log.debug("raf close:", ex); 1445 } 1446 1447 Tools.showInformation(shell, "Save", "Saving user block is successful."); 1448 } 1449 else { 1450 // must rewrite the whole file 1451 MessageDialog confirm = new MessageDialog(shell, "Save", null, 1452 "The user block to write is " + blkSize1 + " (bytes),\n" 1453 + "which is larger than the user block space in file " + blkSize0 + " (bytes).\n" 1454 + "To expand the user block, the file must be rewritten.\n\n" 1455 + "Do you want to replace the current file? Click " 1456 + "\n\"Yes\" to replace the current file," + "\n\"No\" to save to a different file, " 1457 + "\n\"Cancel\" to quit without saving the change.\n\n ", 1458 MessageDialog.QUESTION_WITH_CANCEL, new String[] { "Yes", "No", "Cancel" }, 0); 1459 int op = confirm.open(); 1460 1461 if (op == 2) return; 1462 1463 String fin = obj.getFile(); 1464 1465 String fout = fin + "~copy.h5"; 1466 if (fin.endsWith(".h5")) { 1467 fout = fin.substring(0, fin.length() - 3) + "~copy.h5"; 1468 } 1469 else if (fin.endsWith(".hdf5")) { 1470 fout = fin.substring(0, fin.length() - 5) + "~copy.h5"; 1471 } 1472 1473 File outFile = null; 1474 1475 if (op == 1) { 1476 FileDialog fChooser = new FileDialog(shell, SWT.SAVE); 1477 fChooser.setFileName(fout); 1478 1479 DefaultFileFilter filter = DefaultFileFilter.getFileFilterHDF5(); 1480 fChooser.setFilterExtensions(new String[] { "*", filter.getExtensions() }); 1481 fChooser.setFilterNames(new String[] { "All Files", filter.getDescription() }); 1482 fChooser.setFilterIndex(1); 1483 1484 if (fChooser.open() == null) return; 1485 1486 File chosenFile = new File(fChooser.getFileName()); 1487 1488 outFile = chosenFile; 1489 fout = outFile.getAbsolutePath(); 1490 } 1491 else { 1492 outFile = new File(fout); 1493 } 1494 1495 if (!outFile.exists()) { 1496 try { 1497 if (!outFile.createNewFile()) 1498 log.debug("Error creating file {}", fout); 1499 } 1500 catch (Exception ex) { 1501 Tools.showError(shell, "Save", "Failed to write user block into file."); 1502 return; 1503 } 1504 } 1505 1506 // close the file 1507 TreeView view = viewManager.getTreeView(); 1508 1509 try { 1510 view.closeFile(view.getSelectedFile()); 1511 } 1512 catch (Exception ex) { 1513 log.debug("Error closing file {}", fin); 1514 } 1515 1516 if (Tools.setHDF5UserBlock(fin, fout, buf)) { 1517 if (op == 1) { 1518 fin = fout; // open the new file 1519 } 1520 else { 1521 File oldFile = new File(fin); 1522 boolean status = oldFile.delete(); 1523 if (status) { 1524 if (!outFile.renameTo(oldFile)) 1525 log.debug("Error renaming file {}", fout); 1526 } 1527 else { 1528 Tools.showError(shell, "Save", "Cannot replace the current file.\nPlease save to a different file."); 1529 outFile.delete(); 1530 } 1531 } 1532 } 1533 else { 1534 Tools.showError(shell, "Save", "Failed to write user block into file."); 1535 outFile.delete(); 1536 } 1537 1538 // reopen the file 1539 shell.dispose(); 1540 1541 try { 1542 int access_mode = FileFormat.WRITE; 1543 if (ViewProperties.isReadOnly()) 1544 access_mode = FileFormat.READ; 1545 else if (ViewProperties.isReadSWMR()) 1546 access_mode = FileFormat.READ | FileFormat.MULTIREAD; 1547 view.openFile(fin, access_mode); 1548 } 1549 catch (Exception ex) { 1550 log.debug("Error opening file {}", fin); 1551 } 1552 } 1553 } 1554 } 1555}