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