// // MetadataPane.java // /* OME Metadata Viewer tool for simple exploration of OME-XML metadata. Copyright (C) 2006-@year@ Curtis Rueden. This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package loci.ome.viewer; import java.awt.BorderLayout; import java.awt.Dimension; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.Enumeration; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTable; import javax.swing.JTextArea; import javax.swing.JTree; import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.table.DefaultTableModel; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.DefaultTreeSelectionModel; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; import loci.common.DataTools; import loci.common.RandomAccessInputStream; import loci.formats.tiff.TiffParser; import ome.xml.DOMUtil; import org.openmicroscopy.xml.OMENode; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; /** * MetadataPane is a panel that displays OME-XML metadata. * * <dl><dt><b>Source code:</b></dt> * <dd><a href="http://trac.openmicroscopy.org.uk/ome/browser/bioformats.git/components/legacy/ome-editor/src/loci/ome/viewer/MetadataPane.java">Trac</a>, * <a href="http://git.openmicroscopy.org/?p=bioformats.git;a=blob;f=components/legacy/ome-editor/src/loci/ome/viewer/MetadataPane.java;hb=HEAD">Gitweb</a></dd></dl> */ public class MetadataPane extends JPanel implements Runnable, TreeSelectionListener { // -- Constants -- /** Column headings for OME-XML attributes table. */ protected static final String[] TREE_COLUMNS = {"Attribute", "Value"}; // -- Fields - XML tree -- /** Pane containing XML tree. */ protected JSplitPane xmlTree; /** Tree displaying metadata in OME-XML format. */ protected JTree tree; /** Field listing CDATA for the given XML element. */ protected JTextArea cdata; /** Table listing OME-XML attributes. */ protected JTable treeTable; /** Table model backing OME-XML attributes table. */ protected DefaultTableModel treeTableModel; // -- Fields - raw panel -- /** Panel containing raw XML dump. */ protected JPanel rawPanel; /** Text area displaying raw XML. */ protected JTextArea rawText; /** Whether XML is being displayed in raw form. */ protected boolean raw; // -- Constructor -- /** Constructs widget for displaying OME-XML metadata. */ public MetadataPane() { // -- XML tree -- // OME-XML tree tree = new JTree(new DefaultMutableTreeNode()); JScrollPane scrollTree = new JScrollPane(tree); scrollTree.setPreferredSize(new Dimension(250, 0)); //SwingUtil.configureScrollPane(scrollTree); tree.setRootVisible(false); tree.setShowsRootHandles(true); DefaultTreeSelectionModel treeSelModel = new DefaultTreeSelectionModel(); treeSelModel.setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); tree.setSelectionModel(treeSelModel); tree.addTreeSelectionListener(this); // attributes pane JPanel attributesPane = new JPanel(); attributesPane.setLayout(new BoxLayout(attributesPane, BoxLayout.Y_AXIS)); // CDATA text field cdata = new JTextArea(); cdata.setRows(4); cdata.setEditable(false); JScrollPane cdataScroll = new JScrollPane(cdata); int height = cdata.getPreferredSize().height; cdataScroll.setMaximumSize(new Dimension(Integer.MAX_VALUE, height)); attributesPane.add(cdataScroll); attributesPane.add(Box.createVerticalStrut(5)); // OME-XML attributes table treeTableModel = new DefaultTableModel(TREE_COLUMNS, 0) { public boolean isCellEditable(int row, int col) { return false; } }; treeTable = new JTable(treeTableModel); treeTable.getColumnModel().getColumn(0).setPreferredWidth(100); treeTable.getColumnModel().getColumn(1).setPreferredWidth(300); JScrollPane scrollTreeTable = new JScrollPane(treeTable); //SwingUtil.configureScrollPane(scrollTreeTable); treeTable.setPreferredScrollableViewportSize(new Dimension(400, 0)); attributesPane.add(scrollTreeTable); // OME-XML split pane xmlTree = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, scrollTree, attributesPane); // lay out components setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); add(xmlTree); // -- Raw panel -- rawPanel = new JPanel(); rawPanel.setLayout(new BorderLayout()); // label explaining what happened JLabel rawLabel = new JLabel("Metadata parsing failed. " + "Here is the raw info. Good luck!"); rawLabel.setBorder(new EmptyBorder(5, 0, 5, 0)); rawPanel.add(rawLabel, BorderLayout.NORTH); // text area for displaying raw XML rawText = new JTextArea(); rawText.setLineWrap(true); rawText.setColumns(50); rawText.setRows(30); rawText.setEditable(false); rawPanel.add(new JScrollPane(rawText), BorderLayout.CENTER); rawPanel.setVisible(false); add(rawPanel); } // -- MetadataPane API methods -- /** * Sets the displayed OME-XML metadata to correspond * to the given character string of XML. */ public void setOMEXML(String xml) { OMENode ome = null; try { ome = new OMENode(xml); } catch (Exception exc) { } raw = ome == null; if (raw) rawText.setText(xml); else setOMEXML(ome); SwingUtilities.invokeLater(this); } /** * Sets the displayed OME-XML metadata to correspond * to the given OME-XML or OME-TIFF file. * @return true if the operation was successful */ public boolean setOMEXML(File file) { try { RandomAccessInputStream in = new RandomAccessInputStream(file.getAbsolutePath()); TiffParser parser = new TiffParser(in); if (parser.isValidHeader()) { // TIFF file String xml = parser.getComment(); in.close(); if (xml == null) return false; setOMEXML(xml); } else { String xml = DataTools.readFile(file.getAbsolutePath()); if (xml.startsWith("<?xml") || xml.startsWith("<OME")) { setOMEXML(xml); } else return false; } return true; } catch (IOException exc) { return false; } } /** Sets the displayed OME-XML metadata. */ public void setOMEXML(OMENode ome) { // populate OME-XML tree Document doc = null; try { doc = ome == null ? null : ome.getOMEDocument(false); } catch (Exception exc) { } DefaultMutableTreeNode treeRoot = new DefaultMutableTreeNode(); ((DefaultTreeModel) tree.getModel()).setRoot(treeRoot); if (doc != null) { buildTree(doc.getDocumentElement(), treeRoot); expandTree(tree, treeRoot); } } // -- Component API methods -- /** Sets the initial size of the metadata pane to be reasonable. */ public Dimension getPreferredSize() { return new Dimension(700, 500); } // -- Runnable API methods -- /** Shows or hides the proper subpanes. */ public void run() { xmlTree.setVisible(!raw); rawPanel.setVisible(raw); validate(); repaint(); } // -- TreeSelectionListener API methods -- /** Called when the OME-XML tree selection changes. */ public void valueChanged(TreeSelectionEvent e) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) e.getPath().getLastPathComponent(); if (node == null) { treeTableModel.setRowCount(0); return; } // update CDATA text area Element el = ((ElementWrapper) node.getUserObject()).el; String text = DOMUtil.getCharacterData(el); cdata.setText(text == null ? "" : text); // update OME-XML attributes table String[] names = DOMUtil.getAttributeNames(el); String[] values = DOMUtil.getAttributeValues(el); treeTableModel.setRowCount(names.length); for (int i=0; i<names.length; i++) { treeTableModel.setValueAt(names[i], i, 0); treeTableModel.setValueAt(values[i], i, 1); } } // -- Helper methods -- /** Builds a tree by wrapping XML elements with JTree nodes. */ protected void buildTree(Element el, DefaultMutableTreeNode node) { DefaultMutableTreeNode child = new DefaultMutableTreeNode(new ElementWrapper(el)); node.add(child); NodeList nodeList = el.getChildNodes(); for (int i=0; i<nodeList.getLength(); i++) { Node n = (Node) nodeList.item(i); if (n instanceof Element) buildTree((Element) n, child); } } // -- Utility methods -- /** Fully expands the given JTree from the specified node. */ public static void expandTree(JTree tree, DefaultMutableTreeNode node) { if (node.isLeaf()) return; tree.expandPath(new TreePath(node.getPath())); Enumeration e = node.children(); while (e.hasMoreElements()) { expandTree(tree, (DefaultMutableTreeNode) e.nextElement()); } } // -- Helper classes -- /** Helper class for OME-XML metadata tree view. */ public class ElementWrapper { public Element el; public ElementWrapper(Element el) { this.el = el; } public String toString() { return el == null ? "null" : el.getTagName(); } } }