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 http://hdfgroup.org/products/hdf-java/doc/Copyright.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; 016 017import java.awt.BorderLayout; 018import java.awt.Dimension; 019import java.awt.GridLayout; 020import java.awt.Insets; 021import java.awt.Point; 022import java.awt.event.ActionEvent; 023import java.awt.event.ActionListener; 024import java.awt.event.KeyEvent; 025import java.io.File; 026import java.lang.reflect.Array; 027import java.math.BigInteger; 028import java.util.Enumeration; 029import java.util.List; 030import java.util.StringTokenizer; 031 032import javax.swing.BorderFactory; 033import javax.swing.CellEditor; 034import javax.swing.JButton; 035import javax.swing.JComboBox; 036import javax.swing.JDialog; 037import javax.swing.JFileChooser; 038import javax.swing.JFrame; 039import javax.swing.JInternalFrame; 040import javax.swing.JLabel; 041import javax.swing.JOptionPane; 042import javax.swing.JPanel; 043import javax.swing.JScrollPane; 044import javax.swing.JSplitPane; 045import javax.swing.JTabbedPane; 046import javax.swing.JTable; 047import javax.swing.JTextArea; 048import javax.swing.JTextField; 049import javax.swing.ListSelectionModel; 050import javax.swing.border.TitledBorder; 051import javax.swing.event.ChangeEvent; 052import javax.swing.table.DefaultTableModel; 053import javax.swing.tree.DefaultMutableTreeNode; 054 055import hdf.object.Attribute; 056import hdf.object.CompoundDS; 057import hdf.object.Dataset; 058import hdf.object.Datatype; 059import hdf.object.FileFormat; 060import hdf.object.Group; 061import hdf.object.HObject; 062import hdf.object.ScalarDS; 063 064/** 065 * DefaultMetadataView is an dialog window used to show data properties. Data 066 * properties include attributes and general information such as object type, 067 * data type and data space. 068 * 069 * @author Peter X. Cao 070 * @version 2.4 9/6/2007 071 */ 072public class DefaultMetaDataView extends JDialog implements ActionListener, MetaDataView { 073 private static final long serialVersionUID = 7891048909810508761L; 074 075 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(DefaultMetaDataView.class); 076 077 /** 078 * The main HDFView. 079 */ 080 private ViewManager viewer; 081 082 /** The HDF data object */ 083 private HObject hObject; 084 085 private JTabbedPane tabbedPane = null; 086 private JTextArea attrContentArea; 087 private JTable attrTable; // table to hold a list of attributes 088 private DefaultTableModel attrTableModel; 089 private JLabel attrNumberLabel; 090 private int numAttributes; 091 private boolean isH5, isH4; 092 private byte[] userBlock; 093 private JTextArea userBlockArea; 094 private JButton jamButton; 095 096 private JTextField linkField = null; 097 098 private FileFormat fileFormat; 099 private String LinkTObjName; 100 101 private int[] libver; 102 103 /** 104 * Constructs a DefaultMetadataView with the given HDFView. 105 * 106 * @param theView The main HDFView 107 */ 108 public DefaultMetaDataView(ViewManager theView) { 109 super((JFrame) theView, false); 110 setDefaultCloseOperation(JInternalFrame.DISPOSE_ON_CLOSE); 111 112 setName("DefaultMetaDataView"); 113 viewer = theView; 114 hObject = viewer.getTreeView().getCurrentObject(); 115 fileFormat = hObject.getFileFormat(); 116 numAttributes = 0; 117 userBlock = null; 118 userBlockArea = null; 119 libver = new int[2]; 120 121 if (hObject == null) { 122 dispose(); 123 } 124 else if (hObject.getPath() == null) { 125 setTitle("Properties - " + hObject.getName()); 126 } 127 else { 128 setTitle("Properties - " + hObject.getPath() + hObject.getName()); 129 } 130 131 isH5 = hObject.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF5)); 132 isH4 = hObject.getFileFormat().isThisType(FileFormat.getFileFormat(FileFormat.FILE_TYPE_HDF4)); 133 134 tabbedPane = new JTabbedPane(); 135 // get the metadata information before add GUI components */ 136 try { 137 log.trace("DefaultMetaDataView: start"); 138 hObject.getMetadata(); 139 } 140 catch (Exception ex) { 141 log.debug("get the metadata information before add GUI components:", ex); 142 } 143 tabbedPane.addTab("General", createGeneralPropertyPanel()); 144 tabbedPane.addTab("Attributes", createAttributePanel()); 145 146 boolean isRoot = ((hObject instanceof Group) && ((Group) hObject).isRoot()); 147 if (isH5 && isRoot) { 148 // add panel to display user block 149 tabbedPane.addTab("User Block", createUserBlockPanel()); 150 } 151 tabbedPane.setSelectedIndex(0); 152 153 if (isH5) { 154 if (hObject.getLinkTargetObjName() != null) { 155 LinkTObjName = hObject.getLinkTargetObjName(); 156 } 157 } 158 JPanel bPanel = new JPanel(); 159 bPanel.setName("MetaDataClose"); 160 JButton b = new JButton(" Close "); 161 b.setName("Close"); 162 b.setMnemonic(KeyEvent.VK_C); 163 b.setActionCommand("Close"); 164 b.addActionListener(this); 165 bPanel.add(b); 166 167 // Add the tabbed pane to this panel. 168 JPanel contentPane = (JPanel) getContentPane(); 169 contentPane.setName("MetaDataContent"); 170 contentPane.setLayout(new BorderLayout()); 171 contentPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 172 contentPane.setPreferredSize(new Dimension(620, 400)); 173 174 contentPane.add("Center", tabbedPane); 175 contentPane.add("South", bPanel); 176 177 // locate the H5Property dialog 178 Point l = getParent().getLocation(); 179 l.x += 250; 180 l.y += 80; 181 setLocation(l); 182 pack(); 183 setVisible(true); 184 } 185 186 @SuppressWarnings("rawtypes") 187 public void actionPerformed(ActionEvent e) { 188 Object source = e.getSource(); 189 String cmd = e.getActionCommand(); 190 191 if (cmd.equals("Close")) { 192 if (isH5 && linkField != null) checkLinkTargetChanged(); 193 194 dispose(); 195 } 196 else if (cmd.equals("Add attribute")) { 197 addAttribute(hObject); 198 } 199 else if (cmd.equals("Delete attribute")) { 200 deleteAttribute(hObject); 201 } 202 else if (cmd.equals("Jam user block")) { 203 writeUserBlock(); 204 } 205 else if (cmd.equals("Display user block as")) { 206 int type = 0; 207 String typeName = (String) ((JComboBox) source).getSelectedItem(); 208 jamButton.setEnabled(false); 209 userBlockArea.setEditable(false); 210 211 if (typeName.equalsIgnoreCase("Text")) { 212 type = 0; 213 jamButton.setEnabled(true); 214 userBlockArea.setEditable(true); 215 } 216 else if (typeName.equalsIgnoreCase("Binary")) { 217 type = 2; 218 } 219 else if (typeName.equalsIgnoreCase("Octal")) { 220 type = 8; 221 } 222 else if (typeName.equalsIgnoreCase("Hexadecimal")) { 223 type = 16; 224 } 225 else if (typeName.equalsIgnoreCase("Decimal")) { 226 type = 10; 227 } 228 229 showUserBlockAs(type); 230 } 231 } 232 233 private final void checkLinkTargetChanged() { 234 Group pgroup = null; 235 try { 236 pgroup = (Group) hObject.getFileFormat().get(hObject.getPath()); 237 } 238 catch (Exception ex) { 239 log.debug("parent group:", ex); 240 } 241 if (pgroup == null) { 242 JOptionPane.showMessageDialog(this, "Parent group is null.", getTitle(), JOptionPane.ERROR_MESSAGE); 243 return; 244 } 245 246 String target_name = linkField.getText(); 247 if (target_name != null) target_name = target_name.trim(); 248 249 int linkType = Group.LINK_TYPE_SOFT; 250 if (LinkTObjName.contains(FileFormat.FILE_OBJ_SEP)) 251 linkType = Group.LINK_TYPE_EXTERNAL; 252 else if (target_name.equals("/")) // do not allow to link to the root 253 return; 254 255 // no change 256 if (target_name.equals(hObject.getLinkTargetObjName())) return; 257 258 // invalid name 259 if (target_name == null || target_name.length() < 1) return; 260 261 try { 262 fileFormat.createLink(pgroup, hObject.getName(), target_name, linkType); 263 hObject.setLinkTargetObjName(target_name); 264 } 265 catch (Exception ex) { 266 JOptionPane.showMessageDialog(this, ex, getTitle(), JOptionPane.ERROR_MESSAGE); 267 } 268 } 269 270 /** returns the data object displayed in this data viewer */ 271 public HObject getDataObject() { 272 return hObject; 273 } 274 275 /** Disposes of this dataobserver. */ 276 public void dispose() { 277 super.dispose(); 278 } 279 280 /** add an attribute to a data object. */ 281 public Attribute addAttribute(HObject obj) { 282 if (obj == null) { 283 return null; 284 } 285 286 DefaultMutableTreeNode node = (DefaultMutableTreeNode) obj.getFileFormat().getRootNode(); 287 NewAttributeDialog dialog = new NewAttributeDialog(this, obj, node.breadthFirstEnumeration()); 288 dialog.setVisible(true); 289 290 Attribute attr = dialog.getAttribute(); 291 if (attr == null) { 292 return null; 293 } 294 295 String rowData[] = new String[4]; // name, value, type, size 296 297 rowData[0] = attr.getName(); 298 rowData[2] = attr.getType().getDatatypeDescription(); 299 300 rowData[1] = attr.toString(", "); 301 302 long dims[] = attr.getDataDims(); 303 304 rowData[3] = String.valueOf(dims[0]); 305 for (int j = 1; j < dims.length; j++) { 306 rowData[3] += " x " + dims[j]; 307 } 308 309 attrTableModel.addRow(rowData); 310 attrTableModel.fireTableRowsInserted(attrTableModel.getRowCount() - 1, attrTableModel.getRowCount() - 1); 311 numAttributes++; 312 attrContentArea.setText(""); 313 attrNumberLabel.setText("Number of attributes = " + numAttributes); 314 315 return attr; 316 } 317 318 /** delete an attribute from a data object. */ 319 public Attribute deleteAttribute(HObject obj) { 320 if (obj == null) { 321 return null; 322 } 323 324 int idx = attrTable.getSelectedRow(); 325 if (idx < 0) { 326 JOptionPane.showMessageDialog(getOwner(), "No attribute is selected.", getTitle(), 327 JOptionPane.ERROR_MESSAGE); 328 return null; 329 } 330 331 int option = JOptionPane.showConfirmDialog(this, "Do you want to delete the selected attribute?", getTitle(), 332 JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE); 333 334 if (option == JOptionPane.NO_OPTION) { 335 return null; 336 } 337 338 List<?> attrList = null; 339 try { 340 attrList = obj.getMetadata(); 341 } 342 catch (Exception ex) { 343 attrList = null; 344 } 345 346 if (attrList == null) { 347 return null; 348 } 349 350 Attribute attr = (Attribute) attrList.get(idx); 351 try { 352 obj.removeMetadata(attr); 353 } 354 catch (Exception ex) { 355 log.debug("delete an attribute from a data object:", ex); 356 } 357 358 attrTableModel.removeRow(idx); 359 numAttributes--; 360 attrTableModel.fireTableRowsDeleted(idx, idx); 361 362 attrContentArea.setText(""); 363 attrNumberLabel.setText("Number of attributes = " + numAttributes); 364 365 return attr; 366 } 367 368 /** 369 * Creates a panel used to display general information of HDF object. 370 */ 371 private JPanel createGeneralPropertyPanel() { 372 JPanel panel = new JPanel(); 373 panel.setLayout(new BorderLayout(10, 10)); 374 panel.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0)); 375 boolean isRoot = ((hObject instanceof Group) && ((Group) hObject).isRoot()); 376 FileFormat theFile = hObject.getFileFormat(); 377 378 JPanel topPanel = new JPanel(); 379 topPanel.setLayout(new BorderLayout()); 380 381 JPanel lp = new JPanel(); 382 lp.setLayout(new GridLayout(5, 1)); 383 384 if (isRoot) { 385 lp.add(new JLabel("File Name: ")); 386 lp.add(new JLabel("File Path: ")); 387 lp.add(new JLabel("File Type: ")); 388 if (isH5) { 389 try { 390 libver = hObject.getFileFormat().getLibBounds(); 391 } 392 catch (Exception ex) { 393 ex.printStackTrace(); 394 } 395 if (((libver[0] == 0) || (libver[0] == 1)) && (libver[1] == 1)) 396 lp.add(new JLabel("Library version: ")); 397 } 398 } 399 else { 400 lp.add(new JLabel("Name: ")); 401 if (isH5) { 402 if (hObject.getLinkTargetObjName() != null) lp.add(new JLabel("Link To Target: ")); 403 } 404 lp.add(new JLabel("Path: ")); 405 lp.add(new JLabel("Type: ")); 406 407 /* bug #926 to remove the OID, put it back on Nov. 20, 2008, --PC */ 408 if (isH4) { 409 lp.add(new JLabel("Tag, Ref: ")); 410 } 411 else { 412 lp.add(new JLabel("Object Ref: ")); 413 } 414 } 415 416 JPanel rp = new JPanel(); 417 rp.setLayout(new GridLayout(5, 1)); 418 419 JLabel nameField = new JLabel(hObject.getName()); 420 nameField.setName("namefield"); 421 rp.add(nameField); 422 423 JPanel targetObjPanel = new JPanel(); 424 JButton ChangeTargetObjButton = new JButton("Change"); 425 ChangeTargetObjButton.setActionCommand("Change link target"); 426 ChangeTargetObjButton.addActionListener(this); 427 428 if (isH5) { 429 if (hObject.getLinkTargetObjName() != null) { 430 linkField = new JTextField(hObject.getLinkTargetObjName()); 431 linkField.setName("linkField"); 432 targetObjPanel.setLayout(new BorderLayout()); 433 targetObjPanel.add(linkField, BorderLayout.CENTER); 434 // targetObjPanel.add(ChangeTargetObjButton, BorderLayout.EAST); 435 rp.add(targetObjPanel); 436 } 437 } 438 439 JLabel pathField = new JLabel(); 440 if (isRoot) { 441 pathField.setText((new File(hObject.getFile())).getParent()); 442 } 443 else { 444 pathField.setText(hObject.getPath()); 445 } 446 rp.add(pathField); 447 448 String typeStr = "Unknown"; 449 String fileInfo = ""; 450 if (isRoot) { 451 long size = 0; 452 try { 453 size = (new File(hObject.getFile())).length(); 454 } 455 catch (Exception ex) { 456 size = -1; 457 } 458 size /= 1024; 459 460 int groupCount = 0, datasetCount = 0; 461 DefaultMutableTreeNode root = (DefaultMutableTreeNode) theFile.getRootNode(); 462 DefaultMutableTreeNode theNode = null; 463 Enumeration<?> local_enum = root.depthFirstEnumeration(); 464 while (local_enum.hasMoreElements()) { 465 theNode = (DefaultMutableTreeNode) local_enum.nextElement(); 466 if (theNode.getUserObject() instanceof Group) { 467 groupCount++; 468 } 469 else { 470 datasetCount++; 471 } 472 } 473 fileInfo = "size=" + size + "K, groups=" + groupCount + ", datasets=" + datasetCount; 474 } 475 476 if (isRoot) { 477 if (isH5) { 478 typeStr = "HDF5, " + fileInfo; 479 } 480 else if (isH4) { 481 typeStr = "HDF4, " + fileInfo; 482 } 483 else { 484 typeStr = fileInfo; 485 } 486 } 487 else if (isH5) { 488 if (hObject instanceof Group) { 489 typeStr = "HDF5 Group"; 490 } 491 else if (hObject instanceof ScalarDS) { 492 typeStr = "HDF5 Scalar Dataset"; 493 } 494 else if (hObject instanceof CompoundDS) { 495 typeStr = "HDF5 Compound Dataset"; 496 } 497 else if (hObject instanceof Datatype) { 498 typeStr = "HDF5 Named Datatype"; 499 } 500 } 501 else if (isH4) { 502 if (hObject instanceof Group) { 503 typeStr = "HDF4 Group"; 504 } 505 else if (hObject instanceof ScalarDS) { 506 ScalarDS ds = (ScalarDS) hObject; 507 if (ds.isImage()) { 508 typeStr = "HDF4 Raster Image"; 509 } 510 else { 511 typeStr = "HDF4 SDS"; 512 } 513 } 514 else if (hObject instanceof CompoundDS) { 515 typeStr = "HDF4 Vdata"; 516 } 517 } 518 else { 519 if (hObject instanceof Group) { 520 typeStr = "Group"; 521 } 522 else if (hObject instanceof ScalarDS) { 523 typeStr = "Scalar Dataset"; 524 } 525 else if (hObject instanceof CompoundDS) { 526 typeStr = "Compound Dataset"; 527 } 528 } 529 530 JLabel typeField = new JLabel(typeStr); 531 rp.add(typeField); 532 533 if (isRoot && isH5) { 534 String libversion = null; 535 if ((libver[0] == 0) && (libver[1] == 1)) 536 libversion = "Earliest and Latest"; 537 else if ((libver[0] == 1) && (libver[1] == 1)) libversion = "Latest and Latest"; 538 JLabel libverbound = new JLabel(libversion); 539 libverbound.setName("libverbound"); 540 rp.add(libverbound); 541 } 542 543 /* bug #926 to remove the OID, put it back on Nov. 20, 2008, --PC */ 544 String oidStr = null; 545 long[] OID = hObject.getOID(); 546 if (OID != null) { 547 oidStr = String.valueOf(OID[0]); 548 for (int i = 1; i < OID.length; i++) { 549 oidStr += ", " + OID[i]; 550 } 551 } 552 553 if (!isRoot) { 554 JLabel oidField = new JLabel(oidStr); 555 rp.add(oidField); 556 } 557 558 JPanel tmpP = new JPanel(); 559 tmpP.setLayout(new BorderLayout()); 560 tmpP.add("West", lp); 561 tmpP.add("Center", rp); 562 tmpP.setBorder(new TitledBorder("")); 563 564 topPanel.add("North", new JLabel("")); 565 topPanel.add("Center", tmpP); 566 567 JPanel infoPanel = null; 568 if (hObject instanceof Group) { 569 infoPanel = createGroupInfoPanel((Group) hObject); 570 } 571 else if (hObject instanceof Dataset) { 572 infoPanel = createDatasetInfoPanel((Dataset) hObject); 573 } 574 else if (hObject instanceof Datatype) { 575 infoPanel = createNamedDatatypeInfoPanel((Datatype) hObject); 576 } 577 578 panel.add(topPanel, BorderLayout.NORTH); 579 if (infoPanel != null) { 580 panel.add(infoPanel, BorderLayout.CENTER); 581 } 582 583 return panel; 584 } 585 586 /** 587 * Creates a panel used to display HDF group information. 588 */ 589 private JPanel createGroupInfoPanel(Group g) { 590 JPanel panel = new JPanel(); 591 592 List<?> mlist = g.getMemberList(); 593 if (mlist == null) { 594 return panel; 595 } 596 597 int n = mlist.size(); 598 if (n <= 0) { 599 return panel; 600 } 601 602 String rowData[][] = new String[n][2]; 603 for (int i = 0; i < n; i++) { 604 HObject theObj = (HObject) mlist.get(i); 605 rowData[i][0] = theObj.getName(); 606 if (theObj instanceof Group) { 607 rowData[i][1] = "Group"; 608 } 609 else if (theObj instanceof Dataset) { 610 rowData[i][1] = "Dataset"; 611 } 612 } 613 614 String[] columnNames = { "Name", "Type" }; 615 JTable table = new JTable(rowData, columnNames) { 616 private static final long serialVersionUID = -834321929059590629L; 617 618 public boolean isCellEditable(int row, int column) { 619 return false; 620 } 621 }; 622 table.setName("GroupInfo"); 623 table.setCellSelectionEnabled(false); 624 625 // set cell height for large fonts 626 int cellRowHeight = Math.max(16, table.getFontMetrics(table.getFont()).getHeight()); 627 table.setRowHeight(cellRowHeight); 628 629 table.getTableHeader().setReorderingAllowed(false); 630 JScrollPane scroller = new JScrollPane(table); 631 632 panel.setLayout(new BorderLayout()); 633 if (g.getNumberOfMembersInFile() < ViewProperties.getMaxMembers()) { 634 panel.add(new JLabel("Number of members: " + n), BorderLayout.NORTH); 635 } 636 else { 637 panel.add(new JLabel("Number of members: " + n + " (in memory), " + g.getNumberOfMembersInFile() 638 + " (in file)"), BorderLayout.NORTH); 639 } 640 panel.add(scroller, BorderLayout.CENTER); 641 panel.setBorder(new TitledBorder("Group Members")); 642 643 return panel; 644 } 645 646 private JPanel createNamedDatatypeInfoPanel(Datatype t) { 647 JPanel panel = new JPanel(); 648 panel.setLayout(new BorderLayout()); 649 JTextArea infoArea = new JTextArea(t.getDatatypeDescription()); 650 infoArea.setEditable(false); 651 652 panel.add(infoArea, BorderLayout.CENTER); 653 654 return panel; 655 } 656 657 /** 658 * Creates a panel used to display HDF dataset information. 659 */ 660 private JPanel createDatasetInfoPanel(Dataset d) { 661 JPanel lp = new JPanel(); 662 lp.setLayout(new GridLayout(4, 1)); 663 lp.add(new JLabel("No. of Dimension(s): ")); 664 lp.add(new JLabel("Dimension Size(s): ")); 665 lp.add(new JLabel("Max Dimension Size(s): ")); 666 lp.add(new JLabel("Data Type: ")); 667 668 JPanel rp = new JPanel(); 669 rp.setLayout(new GridLayout(4, 1)); 670 log.trace("createDatasetInfoPanel: start"); 671 672 if (d.getRank() <= 0) { 673 d.init(); 674 } 675 JTextField txtf = new JTextField("" + d.getRank()); 676 txtf.setName("dimensions"); 677 txtf.setEditable(false); 678 rp.add(txtf); 679 log.trace("createDatasetInfoPanel inited"); 680 681 String dimStr = null; 682 String maxDimStr = null; 683 long dims[] = d.getDims(); 684 long maxDims[] = d.getMaxDims(); 685 if (dims != null) { 686 String[] dimNames = d.getDimNames(); 687 boolean hasDimNames = ((dimNames != null) && (dimNames.length == dims.length)); 688 StringBuffer sb = new StringBuffer(); 689 StringBuffer sb2 = new StringBuffer(); 690 691 sb.append(dims[0]); 692 if (hasDimNames) { 693 sb.append(" ("); 694 sb.append(dimNames[0]); 695 sb.append(")"); 696 } 697 698 if (maxDims[0] < 0) 699 sb2.append("Unlimited"); 700 else 701 sb2.append(maxDims[0]); 702 703 for (int i = 1; i < dims.length; i++) { 704 sb.append(" x "); 705 sb.append(dims[i]); 706 if (hasDimNames) { 707 sb.append(" ("); 708 sb.append(dimNames[i]); 709 sb.append(")"); 710 } 711 712 sb2.append(" x "); 713 if (maxDims[i] < 0) 714 sb2.append("Unlimited"); 715 else 716 sb2.append(maxDims[i]); 717 718 } 719 dimStr = sb.toString(); 720 maxDimStr = sb2.toString(); 721 } 722 txtf = new JTextField(dimStr); 723 txtf.setName("dimensionsize"); 724 txtf.setEditable(false); 725 rp.add(txtf); 726 727 txtf = new JTextField(maxDimStr); 728 txtf.setEditable(false); 729 rp.add(txtf); 730 731 String typeStr = null; 732 if (d instanceof ScalarDS) { 733 ScalarDS sd = (ScalarDS) d; 734 typeStr = sd.getDatatype().getDatatypeDescription(); 735 } 736 else if (d instanceof CompoundDS) { 737 if (isH4) { 738 typeStr = "Vdata"; 739 } 740 else { 741 typeStr = "Compound"; 742 } 743 } 744 745 txtf = new JTextField(typeStr); 746 txtf.setEditable(false); 747 rp.add(txtf); 748 749 JPanel infoP = new JPanel(); 750 infoP.setLayout(new BorderLayout()); 751 infoP.add(lp, BorderLayout.WEST); 752 infoP.add(rp, BorderLayout.CENTER); 753 infoP.setBorder(new TitledBorder("")); 754 755 JPanel panel = new JPanel(); 756 panel.setLayout(new BorderLayout()); 757 panel.add(infoP, BorderLayout.NORTH); 758 panel.setBorder(new TitledBorder("Dataspace and Datatype")); 759 760 // add compound datatype information 761 if (d instanceof CompoundDS) { 762 CompoundDS compound = (CompoundDS) d; 763 764 int n = compound.getMemberCount(); 765 if (n > 0) { 766 String rowData[][] = new String[n][3]; 767 String names[] = compound.getMemberNames(); 768 Datatype types[] = compound.getMemberTypes(); 769 int orders[] = compound.getMemberOrders(); 770 771 for (int i = 0; i < n; i++) { 772 rowData[i][0] = names[i]; 773 int mDims[] = compound.getMemberDims(i); 774 if (mDims == null) { 775 rowData[i][2] = String.valueOf(orders[i]); 776 777 if (isH4 && types[i].getDatatypeClass() == Datatype.CLASS_STRING) { 778 rowData[i][2] = String.valueOf(types[i].getDatatypeSize()); 779 } 780 } 781 else { 782 String mStr = String.valueOf(mDims[0]); 783 int m = mDims.length; 784 for (int j = 1; j < m; j++) { 785 mStr += " x " + mDims[j]; 786 } 787 rowData[i][2] = mStr; 788 } 789 rowData[i][1] = types[i].getDatatypeDescription(); 790 } 791 792 String[] columnNames = { "Name", "Type", "Array Size" }; 793 JTable table = new JTable(rowData, columnNames) { 794 private static final long serialVersionUID = -1517773307922536859L; 795 796 public boolean isCellEditable(int row, int column) { 797 return false; 798 } 799 }; 800 table.setName("CompoundMetaData"); 801 table.setCellSelectionEnabled(false); 802 table.getTableHeader().setReorderingAllowed(false); 803 panel.add(new JScrollPane(table), BorderLayout.CENTER); 804 805 // set cell height for large fonts 806 int cellRowHeight = Math.max(16, table.getFontMetrics(table.getFont()).getHeight()); 807 table.setRowHeight(cellRowHeight); 808 } // if (n > 0) 809 } // if (d instanceof Compound) 810 811 // // add compression and data layout information 812 // try { d.getMetadata(); } catch (Exception ex) {} 813 String chunkInfo = ""; 814 long[] chunks = d.getChunkSize(); 815 if (chunks == null) { 816 chunkInfo = "NONE"; 817 } 818 else { 819 int n = chunks.length; 820 chunkInfo = String.valueOf(chunks[0]); 821 for (int i = 1; i < n; i++) { 822 chunkInfo += " X " + chunks[i]; 823 } 824 } 825 826 JPanel bPanel = new JPanel(); 827 bPanel.setBorder(new TitledBorder("")); 828 bPanel.setLayout(new BorderLayout()); 829 lp = new JPanel(); 830 lp.setName("genmetainfo"); 831 lp.setLayout(new GridLayout(5, 1)); 832 lp.add(new JLabel("Chunking: ")); 833 lp.add(new JLabel("Compression: ")); 834 lp.add(new JLabel("Filters: ")); 835 lp.add(new JLabel("Storage: ")); 836 lp.add(new JLabel("Fill value: ")); 837 bPanel.add(lp, BorderLayout.WEST); 838 839 Object fillValue = null; 840 String fillValueInfo = "NONE"; 841 if (d instanceof ScalarDS) fillValue = ((ScalarDS) d).getFillValue(); 842 if (fillValue != null) { 843 if (fillValue.getClass().isArray()) { 844 int len = Array.getLength(fillValue); 845 fillValueInfo = Array.get(fillValue, 0).toString(); 846 for (int i = 1; i < len; i++) { 847 fillValueInfo += ", "; 848 fillValueInfo += Array.get(fillValue, i).toString(); 849 } 850 } 851 else 852 fillValueInfo = fillValue.toString(); 853 } 854 855 rp = new JPanel(); 856 rp.setName("genmetadata"); 857 rp.setLayout(new GridLayout(5, 1)); 858 JLabel rpchunk = new JLabel(chunkInfo); 859 rpchunk.setName("chunkdata"); 860 rp.add(rpchunk); 861 JLabel rpcomp = new JLabel(d.getCompression()); 862 rpcomp.setName("compressiondata"); 863 rp.add(rpcomp); 864 JLabel rpfilt = new JLabel(d.getFilters()); 865 rpfilt.setName("filterdata"); 866 rp.add(rpfilt); 867 JLabel rpstore = new JLabel(d.getStorage()); 868 rpstore.setName("storagedata"); 869 rp.add(rpstore); 870 JLabel rpfillval = new JLabel(fillValueInfo); 871 rpfillval.setName("fillvaluedata"); 872 rp.add(rpfillval); 873 bPanel.add(rp, BorderLayout.CENTER); 874 875 panel.add(bPanel, BorderLayout.SOUTH); 876 log.trace("createDatasetInfoPanel: finish"); 877 878 return panel; 879 } 880 881 /** 882 * Creates a panel used to display attribute information. 883 */ 884 private JPanel createAttributePanel() { 885 JPanel panel = new JPanel(); 886 panel.setLayout(new BorderLayout()); 887 // panel.setBorder(BorderFactory.createEmptyBorder(10,0,0,0)); 888 889 JPanel topPanel = new JPanel(); 890 topPanel.setLayout(new BorderLayout()); 891 attrNumberLabel = new JLabel("Number of attributes = 0"); 892 topPanel.add(attrNumberLabel, BorderLayout.WEST); 893 894 FileFormat theFile = hObject.getFileFormat(); 895 JPanel bPanel = new JPanel(); 896 JButton b = new JButton(" Add "); 897 b.setName("Add"); 898 b.setMnemonic('A'); 899 b.addActionListener(this); 900 b.setActionCommand("Add attribute"); 901 bPanel.add(b); 902 b.setEnabled(!theFile.isReadOnly()); 903 904 if (isH5) { 905 // deleting is not supported by HDF4 906 b = new JButton("Delete"); 907 b.setName("Delete"); 908 b.setMnemonic('D'); 909 b.addActionListener(this); 910 b.setActionCommand("Delete attribute"); 911 bPanel.add(b); 912 b.setEnabled(!theFile.isReadOnly()); 913 } 914 topPanel.add(bPanel, BorderLayout.EAST); 915 916 panel.add(topPanel, BorderLayout.NORTH); 917 918 List<?> attrList = null; 919 log.trace("createAttributePanel: start"); 920 921 try { 922 attrList = hObject.getMetadata(); 923 } 924 catch (Exception ex) { 925 attrList = null; 926 } 927 if (attrList != null) { 928 numAttributes = attrList.size(); 929 } 930 log.trace("createAttributePanel: isH5={} numAttributes={}", isH5, numAttributes); 931 932 String[] columnNames = { "Name", "Value", "Type", "Array Size" }; 933 attrTableModel = new DefaultTableModel(columnNames, numAttributes); 934 935 attrTable = new JTable(attrTableModel) { 936 private static final long serialVersionUID = 2590244645972259454L; 937 int lastSelectedRow = -1; 938 int lastSelectedCol = -1; 939 940 public boolean isCellEditable(int row, int column) { 941 return ((column == 1) || (isH5 && (column == 0))); 942 // only attribute value and name can be changed 943 } 944 945 public void editingStopped(ChangeEvent e) { 946 int row = getEditingRow(); 947 int col = getEditingColumn(); 948 String oldValue = (String) getValueAt(row, col); 949 950 super.editingStopped(e); 951 952 Object source = e.getSource(); 953 954 if (source instanceof CellEditor) { 955 CellEditor editor = (CellEditor) source; 956 String newValue = (String) editor.getCellEditorValue(); 957 setValueAt(oldValue, row, col); // set back to what it is 958 updateAttributeValue(newValue, row, col); 959 } 960 } 961 962 public boolean isCellSelected(int row, int col) { 963 964 if ((getSelectedRow() == row) && (getSelectedColumn() == col) 965 && !((lastSelectedRow == row) && (lastSelectedCol == col))) { 966 // selection is changed 967 Object attrV = getValueAt(row, col); 968 if (attrV != null) { 969 attrContentArea.setText(attrV.toString()); 970 } 971 lastSelectedRow = row; 972 lastSelectedCol = col; 973 } 974 975 return super.isCellSelected(row, col); 976 } 977 }; 978 979 attrTable.setName("attributes"); 980 attrTable.setRowSelectionAllowed(false); 981 attrTable.setCellSelectionEnabled(true); 982 attrTable.getTableHeader().setReorderingAllowed(false); 983 attrTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 984 985 // set cell height for large fonts 986 int cellRowHeight = Math.max(16, attrTable.getFontMetrics(attrTable.getFont()).getHeight()); 987 attrTable.setRowHeight(cellRowHeight); 988 989 JScrollPane scroller1 = new JScrollPane(attrTable); 990 attrContentArea = new JTextArea(); 991 attrContentArea.setLineWrap(true); 992 attrContentArea.setEditable(false); 993 Insets m = new Insets(5, 5, 5, 5); 994 attrContentArea.setMargin(m); 995 996 JScrollPane scroller2 = new JScrollPane(attrContentArea); 997 JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, scroller1, scroller2); 998 999 // set the divider location 1000 int h = Math.min((numAttributes + 2) * attrTable.getRowHeight(), scroller1.getPreferredSize().height - 40); 1001 splitPane.setDividerLocation(h); 1002 panel.add(splitPane, BorderLayout.CENTER); 1003 1004 if (attrList == null) { 1005 log.trace("createAttributePanel: attrList == null"); 1006 return panel; 1007 } 1008 1009 Attribute attr = null; 1010 String name, type, size; 1011 attrNumberLabel.setText("Number of attributes = " + numAttributes); 1012 for (int i = 0; i < numAttributes; i++) { 1013 attr = (Attribute) attrList.get(i); 1014 name = attr.getName(); 1015 type = attr.getType().getDatatypeDescription(); 1016 log.trace("createAttributePanel: attr[{}] is {} as {}", i, name, type); 1017 1018 if (attr.isScalar()) { 1019 size = "Scalar"; 1020 } 1021 else { 1022 long dims[] = attr.getDataDims(); 1023 size = String.valueOf(dims[0]); 1024 for (int j = 1; j < dims.length; j++) { 1025 size += " x " + dims[j]; 1026 } 1027 } 1028 1029 if (attr.getProperty("field") !=null) { 1030 String fieldInfo = " {Field: "+attr.getProperty("field")+"}"; 1031 attrTable.setValueAt(name+fieldInfo, i, 0); 1032 } 1033 else 1034 attrTable.setValueAt(name, i, 0); 1035 1036 attrTable.setValueAt(attr.toString(", "), i, 1); 1037 attrTable.setValueAt(type, i, 2); 1038 attrTable.setValueAt(size, i, 3); 1039 } // for (int i=0; i<n; i++) 1040 1041 log.trace("createAttributePanel: finish"); 1042 return panel; 1043 } 1044 1045 /** 1046 * Creates a panel used to display HDF5 user block. 1047 */ 1048 @SuppressWarnings({ "rawtypes", "unchecked" }) 1049 private JPanel createUserBlockPanel() { 1050 JPanel panel = new JPanel(); 1051 1052 userBlock = DefaultFileFilter.getHDF5UserBlock(hObject.getFile()); 1053 1054 panel.setLayout(new BorderLayout(10, 10)); 1055 panel.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0)); 1056 userBlockArea = new JTextArea(); 1057 userBlockArea.setEditable(true); 1058 userBlockArea.setLineWrap(true); 1059 Insets m = new Insets(5, 5, 5, 5); 1060 userBlockArea.setMargin(m); 1061 1062 String[] displayChoices = { "Text", "Binary", "Octal", "Hexadecimal", "Decimal" }; 1063 JComboBox userBlockDisplayChoice = new JComboBox(displayChoices); 1064 userBlockDisplayChoice.setSelectedIndex(0); 1065 userBlockDisplayChoice.addActionListener(this); 1066 userBlockDisplayChoice.setEditable(false); 1067 userBlockDisplayChoice.setActionCommand("Display user block as"); 1068 1069 JLabel sizeLabel = new JLabel("Header Size (Bytes): 0"); 1070 jamButton = new JButton("Save User Block"); 1071 jamButton.setActionCommand("Jam user block"); 1072 jamButton.addActionListener(this); 1073 JPanel topPane = new JPanel(); 1074 topPane.setLayout(new BorderLayout(10, 5)); 1075 topPane.add(new JLabel("Display As:"), BorderLayout.WEST); 1076 JPanel topPane0 = new JPanel(); 1077 topPane0.setLayout(new GridLayout(1, 2, 10, 5)); 1078 topPane0.add(userBlockDisplayChoice); 1079 topPane0.add(sizeLabel); 1080 topPane.add(topPane0, BorderLayout.CENTER); 1081 topPane.add(jamButton, BorderLayout.EAST); 1082 1083 JScrollPane scroller = new JScrollPane(userBlockArea); 1084 panel.add(topPane, BorderLayout.NORTH); 1085 panel.add(scroller, BorderLayout.CENTER); 1086 1087 int headSize = 0; 1088 if (userBlock != null) { 1089 headSize = showUserBlockAs(0); 1090 sizeLabel.setText("Header Size (Bytes): " + headSize); 1091 } 1092 else { 1093 userBlockDisplayChoice.setEnabled(false); 1094 } 1095 1096 return panel; 1097 } 1098 1099 private int showUserBlockAs(int radix) { 1100 int headerSize = 0; 1101 1102 if (userBlock == null) { 1103 return 0; 1104 } 1105 1106 String userBlockInfo = null; 1107 if ((radix == 2) || (radix == 8) || (radix == 16) || (radix == 10)) { 1108 StringBuffer sb = new StringBuffer(); 1109 for (headerSize = 0; headerSize < userBlock.length; headerSize++) { 1110 int intValue = (int) userBlock[headerSize]; 1111 if (intValue < 0) { 1112 intValue += 256; 1113 } 1114 else if (intValue == 0) { 1115 break; // null end 1116 } 1117 sb.append(Integer.toString(intValue, radix)); 1118 sb.append(" "); 1119 } 1120 userBlockInfo = sb.toString(); 1121 } 1122 else { 1123 userBlockInfo = new String(userBlock).trim(); 1124 if (userBlockInfo != null) { 1125 headerSize = userBlockInfo.length(); 1126 } 1127 } 1128 1129 userBlockArea.setText(userBlockInfo); 1130 1131 return headerSize; 1132 } 1133 1134 /** 1135 * update attribute value. Currently can only update single data point. 1136 * 1137 * @param newValue 1138 * the string of the new value. 1139 * @param row 1140 * the row number of the selected cell. 1141 * @param col 1142 * the column number of the selected cell. 1143 */ 1144 private void updateAttributeValue(String newValue, int row, int col) { 1145 log.trace("updateAttributeValue:start value={}[{},{}]", newValue, row, col); 1146 1147 String attrName = (String) attrTable.getValueAt(row, 0); 1148 List<?> attrList = null; 1149 try { 1150 attrList = hObject.getMetadata(); 1151 } 1152 catch (Exception ex) { 1153 JOptionPane.showMessageDialog(getOwner(), ex.getMessage(), getTitle(), JOptionPane.ERROR_MESSAGE); 1154 return; 1155 } 1156 1157 Attribute attr = (Attribute) attrList.get(row); 1158 1159 if (col == 1) { // To change attribute value 1160 log.trace("updateAttributeValue: change attribute value"); 1161 Object data = attr.getValue(); 1162 if (data == null) { 1163 return; 1164 } 1165 1166 int array_length = Array.getLength(data); 1167 StringTokenizer st = new StringTokenizer(newValue, ","); 1168 if (st.countTokens() < array_length) { 1169 JOptionPane.showMessageDialog(getOwner(), "More data value needed: " + newValue, getTitle(), 1170 JOptionPane.ERROR_MESSAGE); 1171 return; 1172 } 1173 1174 char NT = ' '; 1175 String cName = data.getClass().getName(); 1176 int cIndex = cName.lastIndexOf("["); 1177 if (cIndex >= 0) { 1178 NT = cName.charAt(cIndex + 1); 1179 } 1180 boolean isUnsigned = attr.isUnsigned(); 1181 log.trace("updateAttributeValue:start array_length={} cName={} NT={} isUnsigned={}", array_length, cName, NT, isUnsigned); 1182 1183 double d = 0; 1184 String theToken = null; 1185 long max = 0, min = 0; 1186 for (int i = 0; i < array_length; i++) { 1187 max = min = 0; 1188 theToken = st.nextToken().trim(); 1189 try { 1190 if (!(Array.get(data, i) instanceof String)) { 1191 d = Double.parseDouble(theToken); 1192 } 1193 } 1194 catch (NumberFormatException ex) { 1195 JOptionPane.showMessageDialog(getOwner(), ex.getMessage(), getTitle(), JOptionPane.ERROR_MESSAGE); 1196 return; 1197 } 1198 1199 if (isUnsigned && (d < 0)) { 1200 JOptionPane.showMessageDialog(getOwner(), "Negative value for unsigned integer: " + theToken, 1201 getTitle(), JOptionPane.ERROR_MESSAGE); 1202 return; 1203 } 1204 1205 switch (NT) { 1206 case 'B': { 1207 if (isUnsigned) { 1208 min = 0; 1209 max = 255; 1210 } 1211 else { 1212 min = Byte.MIN_VALUE; 1213 max = Byte.MAX_VALUE; 1214 } 1215 1216 if ((d > max) || (d < min)) { 1217 JOptionPane.showMessageDialog(getOwner(), "Data is out of range[" + min + ", " + max 1218 + "]: " + theToken, getTitle(), JOptionPane.ERROR_MESSAGE); 1219 } 1220 else { 1221 Array.setByte(data, i, (byte) d); 1222 } 1223 break; 1224 } 1225 case 'S': { 1226 if (isUnsigned) { 1227 min = 0; 1228 max = 65535; 1229 } 1230 else { 1231 min = Short.MIN_VALUE; 1232 max = Short.MAX_VALUE; 1233 } 1234 1235 if ((d > max) || (d < min)) { 1236 JOptionPane.showMessageDialog(getOwner(), "Data is out of range[" + min + ", " + max 1237 + "]: " + theToken, getTitle(), JOptionPane.ERROR_MESSAGE); 1238 } 1239 else { 1240 Array.setShort(data, i, (short) d); 1241 } 1242 break; 1243 } 1244 case 'I': { 1245 if (isUnsigned) { 1246 min = 0; 1247 max = 4294967295L; 1248 } 1249 else { 1250 min = Integer.MIN_VALUE; 1251 max = Integer.MAX_VALUE; 1252 } 1253 1254 if ((d > max) || (d < min)) { 1255 JOptionPane.showMessageDialog(getOwner(), "Data is out of range[" + min + ", " + max 1256 + "]: " + theToken, getTitle(), JOptionPane.ERROR_MESSAGE); 1257 } 1258 else { 1259 Array.setInt(data, i, (int) d); 1260 } 1261 break; 1262 } 1263 case 'J': 1264 long lvalue = 0; 1265 if (isUnsigned) { 1266 if (theToken != null) { 1267 String theValue = theToken; 1268 BigInteger Jmax = new BigInteger("18446744073709551615"); 1269 BigInteger big = new BigInteger(theValue); 1270 if ((big.compareTo(Jmax)>0) || (big.compareTo(BigInteger.ZERO)<0)) { 1271 JOptionPane.showMessageDialog(getOwner(), "Data is out of range[" + min + ", " + max 1272 + "]: " + theToken, getTitle(), JOptionPane.ERROR_MESSAGE); 1273 } 1274 lvalue = big.longValue(); 1275 log.trace("updateAttributeValue: big.longValue={}", lvalue); 1276 Array.setLong(data, i, lvalue); 1277 } 1278 else 1279 Array.set(data, i, (Object)theToken); 1280 } 1281 else { 1282 min = Long.MIN_VALUE; 1283 max = Long.MAX_VALUE; 1284 if ((d > max) || (d < min)) { 1285 JOptionPane.showMessageDialog(getOwner(), "Data is out of range[" + min + ", " + max 1286 + "]: " + theToken, getTitle(), JOptionPane.ERROR_MESSAGE); 1287 } 1288 lvalue = (long)d; 1289 log.trace("updateAttributeValue: longValue={}", lvalue); 1290 Array.setLong(data, i, lvalue); 1291 } 1292 break; 1293 case 'F': 1294 Array.setFloat(data, i, (float) d); 1295 break; 1296 case 'D': 1297 Array.setDouble(data, i, d); 1298 break; 1299 default: 1300 Array.set(data, i, (Object)theToken); 1301 break; 1302 } 1303 } 1304 1305 try { 1306 hObject.getFileFormat().writeAttribute(hObject, attr, true); 1307 } 1308 catch (Exception ex) { 1309 JOptionPane.showMessageDialog(getOwner(), ex.getMessage(), getTitle(), JOptionPane.ERROR_MESSAGE); 1310 return; 1311 } 1312 1313 // update the attribute table 1314 attrTable.setValueAt(attr.toString(", "), row, 1); 1315 } 1316 1317 if ((col == 0) && isH5) { // To change attribute name 1318 log.trace("updateAttributeValue: change attribute name"); 1319 try { 1320 hObject.getFileFormat().renameAttribute(hObject, attrName, newValue); 1321 } 1322 catch (Exception ex) { 1323 JOptionPane.showMessageDialog(getOwner(), ex.getMessage(), getTitle(), JOptionPane.ERROR_MESSAGE); 1324 return; 1325 } 1326 1327 // update the attribute table 1328 attrTable.setValueAt(newValue, row, 0); 1329 } 1330 if (hObject instanceof ScalarDS) { 1331 ScalarDS ds = (ScalarDS) hObject; 1332 try { 1333 log.trace("updateAttributeValue: ScalarDS:updateMetadata"); 1334 ds.updateMetadata(attr); 1335 } 1336 catch (Exception ex) { 1337 JOptionPane.showMessageDialog(getOwner(), ex.getMessage(), getTitle(), JOptionPane.ERROR_MESSAGE); 1338 } 1339 } 1340 else { 1341 log.trace("updateAttributeValue: hObject is not instanceof ScalarDS"); 1342 } 1343 } 1344 1345 private void writeUserBlock() { 1346 if (!isH5) { 1347 return; 1348 } 1349 1350 int blkSize0 = 0; 1351 if (userBlock != null) { 1352 blkSize0 = userBlock.length; 1353 // The super block space is allocated by offset 0, 512, 1024, 2048, 1354 // etc 1355 if (blkSize0 > 0) { 1356 int offset = 512; 1357 while (offset < blkSize0) { 1358 offset *= 2; 1359 } 1360 blkSize0 = offset; 1361 } 1362 } 1363 1364 int blkSize1 = 0; 1365 String userBlockStr = userBlockArea.getText(); 1366 if (userBlockStr == null) { 1367 if (blkSize0 <= 0) { 1368 return; // nothing to write 1369 } 1370 else { 1371 userBlockStr = " "; // want to wipe out old userblock content 1372 } 1373 } 1374 byte buf[] = null; 1375 buf = userBlockStr.getBytes(); 1376 1377 blkSize1 = buf.length; 1378 if (blkSize1 <= blkSize0) { 1379 java.io.RandomAccessFile raf = null; 1380 try { 1381 raf = new java.io.RandomAccessFile(hObject.getFile(), "rw"); 1382 } 1383 catch (Exception ex) { 1384 JOptionPane.showMessageDialog(this, "Can't open output file: " + hObject.getFile(), getTitle(), 1385 JOptionPane.ERROR_MESSAGE); 1386 return; 1387 } 1388 1389 try { 1390 raf.seek(0); 1391 raf.write(buf, 0, buf.length); 1392 raf.seek(buf.length); 1393 if (blkSize0 > buf.length) { 1394 byte[] padBuf = new byte[blkSize0 - buf.length]; 1395 raf.write(padBuf, 0, padBuf.length); 1396 } 1397 } 1398 catch (Exception ex) { 1399 log.debug("raf write:", ex); 1400 } 1401 try { 1402 raf.close(); 1403 } 1404 catch (Exception ex) { 1405 log.debug("raf close:", ex); 1406 } 1407 1408 JOptionPane.showMessageDialog(this, "Saving user block is successful.", getTitle(), 1409 JOptionPane.INFORMATION_MESSAGE); 1410 } 1411 else { 1412 // must rewrite the whole file 1413 // must rewrite the whole file 1414 int op = JOptionPane.showConfirmDialog(this, 1415 "The user block to write is " + blkSize1 + " (bytes),\n" 1416 + "which is larger than the user block space in file " + blkSize0 + " (bytes).\n" 1417 + "To expand the user block, the file must be rewriten.\n\n" 1418 + "Do you want to replace the current file? Click " 1419 + "\n\"Yes\" to replace the current file," + "\n\"No\" to save to a different file, " 1420 + "\n\"Cancel\" to quit without saving the change.\n\n ", getTitle(), 1421 JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE); 1422 1423 if (op == JOptionPane.CANCEL_OPTION) { 1424 return; 1425 } 1426 1427 String fin = hObject.getFile(); 1428 1429 String fout = fin + "~copy.h5"; 1430 if (fin.endsWith(".h5")) { 1431 fout = fin.substring(0, fin.length() - 3) + "~copy.h5"; 1432 } 1433 else if (fin.endsWith(".hdf5")) { 1434 fout = fin.substring(0, fin.length() - 5) + "~copy.h5"; 1435 } 1436 1437 File outFile = null; 1438 1439 if (op == JOptionPane.NO_OPTION) { 1440 JFileChooser fchooser = new JFileChooser(); 1441 fchooser.setFileFilter(DefaultFileFilter.getFileFilterHDF5()); 1442 fchooser.setSelectedFile(new File(fout)); 1443 1444 int returnVal = fchooser.showSaveDialog(this); 1445 if (returnVal != JFileChooser.APPROVE_OPTION) { 1446 return; 1447 } 1448 1449 File choosedFile = fchooser.getSelectedFile(); 1450 if (choosedFile == null) { 1451 return; 1452 } 1453 1454 outFile = choosedFile; 1455 fout = outFile.getAbsolutePath(); 1456 } 1457 else { 1458 outFile = new File(fout); 1459 } 1460 1461 if (!outFile.exists()) { 1462 try { 1463 outFile.createNewFile(); 1464 } 1465 catch (Exception ex) { 1466 JOptionPane.showMessageDialog(this, "Fail to write user block into file. ", getTitle(), 1467 JOptionPane.ERROR_MESSAGE); 1468 return; 1469 } 1470 } 1471 1472 // close the file 1473 ActionEvent e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "Close file"); 1474 ((HDFView) viewer).actionPerformed(e); 1475 1476 if (DefaultFileFilter.setHDF5UserBlock(fin, fout, buf)) { 1477 if (op == JOptionPane.NO_OPTION) { 1478 fin = fout; // open the new file 1479 } 1480 else { 1481 File oldFile = new File(fin); 1482 boolean status = oldFile.delete(); 1483 if (status) { 1484 outFile.renameTo(oldFile); 1485 } 1486 else { 1487 JOptionPane.showMessageDialog(this, 1488 "Cannot replace the current file.\nPlease save to a different file.", getTitle(), 1489 JOptionPane.ERROR_MESSAGE); 1490 outFile.delete(); 1491 } 1492 } 1493 } 1494 else { 1495 JOptionPane.showMessageDialog(this, "Fail to write user block into file. ", getTitle(), 1496 JOptionPane.ERROR_MESSAGE); 1497 outFile.delete(); 1498 } 1499 1500 // reopen the file 1501 dispose(); 1502 e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED, "Open file://" + fin); 1503 ((HDFView) viewer).actionPerformed(e); 1504 } 1505 } 1506 1507}