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