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