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