/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: ComparisonsTree.java
*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
*
* Electric(tm) is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Electric(tm) 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Electric(tm); see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, Mass 02111-1307, USA.
*/
package com.sun.electric.tool.user.ncc;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTree;
import javax.swing.SwingConstants;
import javax.swing.border.Border;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreePath;
import com.sun.electric.tool.ncc.netlist.NetObject;
import com.sun.electric.tool.ncc.processing.LocalPartitionResult;
import com.sun.electric.tool.ncc.result.EquivRecReport;
import com.sun.electric.tool.ncc.result.NetObjReport;
import com.sun.electric.tool.ncc.trees.Circuit;
/**
* This class implements the mismatch comparin tree displayed in the right pane
* of the NCC GUI window.
*/
class ComparisonsTree extends JTree implements ActionListener, TreeSelectionListener {
/* --- size restrictions --- */
public static final int MAX_COMP_NODES = 100;
public static final int MAX_ZEROS = 100;
public static final int MAX_CLASSES = 200;
public static final int MAX_LIST_ELEMENTS = 200;
public static final int MAX_NAME_LEN = 100;
/* --- GUI variables --- */
private ComparisonsPane parentPane;
private DefaultMutableTreeNode root;
private TreeNode rootTreeNode;
private WireClassNode wireClassNodes[][];
protected JPopupMenu popup;
protected String clipboard;
private static Border border = BorderFactory.createEmptyBorder();
private boolean updateInProgress = true;
/** list of current comparison mismatches */
private NccGuiInfo[] mismatches;
protected ComparisonsTree(ComparisonsPane pane, DefaultMutableTreeNode root) {
super(root);
this.root = root;
rootTreeNode = (TreeNode)root.getUserObject();
parentPane = pane;
setMinimumSize(new Dimension(0,0));
setShowsRootHandles(true);
addMouseListener(new TreeMouseAdapter());
addTreeSelectionListener(this);
createPopup();
setCellRenderer(new MyRenderer());
}
/**
* Create a right-click popup for tree nodes
*/
private void createPopup() {
popup = new JPopupMenu();
JMenuItem menuItem = new JMenuItem("Copy Node Title To Clipboard");
menuItem.addActionListener(this);
popup.add(menuItem);
}
/**
* Update the tree with the provided list of comparison mismatches
* @param misms list of comparison mismatches
*/
protected void update(NccGuiInfo[] misms) {
updateInProgress = true;
mismatches = misms;
wireClassNodes = new WireClassNode[misms.length][];
root.removeAllChildren();
DefaultMutableTreeNode compNode;
EquivRecReport[] mismEqRecs;
// for each comparison in the list
for (int compNdx = 0; compNdx < mismatches.length
&& compNdx < MAX_COMP_NODES; compNdx++) {
NccGuiInfo cm = mismatches[compNdx];
// compute node name from cell names
String titles[] = cm.getNames();
String title0 = titles[0].substring(0,titles[0].length()-5);
String title1 = titles[1].substring(0,titles[1].length()-5);
String title;
if (title1.equals(title0))
title = title0 + "{sch,lay}";
else
title = titles[0] + " & " + titles[1];
// create top-level tree node
TreeNode compTreeNode = new TreeNode(rootTreeNode,
title + " [" + cm.getTotalMismatchCount() + "]",
compNdx, -1, TreeNode.COMP_TITLE);
compTreeNode.setShortName(title);
compNode = new DefaultMutableTreeNode(compTreeNode);
root.add(compNode);
// add exports entry if necessary
int exportMismCount = cm.getValidExportMismatchCount();
String exportsTitle = null;
if (exportMismCount > 0) {
if (exportMismCount > ExportTable.MAXROWS) {
exportsTitle = "Exports [first " + ExportTable.MAXROWS
+ " of " + exportMismCount + "]";
exportMismCount = ExportTable.MAXROWS;
} else if (exportMismCount > 0) {
exportsTitle = "Exports [" + exportMismCount + "]";
}
compNode.add(new DefaultMutableTreeNode(
new TreeNode(compTreeNode, exportsTitle,
compNdx, -1, TreeNode.EXPORTS)));
}
boolean isHashChecked = cm.isHashFailuresPrinted();
// collect part/wire equiv records
int size = cm.getWireRecReports().size() + cm.getPartRecReports().size();
mismEqRecs = new EquivRecReport[size];
int i=0;
for (EquivRecReport r : cm.getPartRecReports()) mismEqRecs[i++] = r;
for (EquivRecReport r : cm.getWireRecReports()) mismEqRecs[i++] = r;
parentPane.setMismatchEquivRecs(compNdx, mismEqRecs);
if (mismEqRecs != null && mismEqRecs.length > 0) {
// add parts entry
addPartClasses(compTreeNode, compNdx, compNode, mismEqRecs, isHashChecked);
// add wires entry
addWireClasses(compTreeNode, compNdx, compNode, mismEqRecs, isHashChecked);
}
// add sizes entry, if necessary
int sizeMismCount = cm.getSizeMismatches().size();
String sizeTitle = null;
if (sizeMismCount > SizeMismatchPane.MAXROWS) {
sizeTitle = "Sizes [first " + SizeMismatchPane.MAXROWS
+ " of " + sizeMismCount + "]";
sizeMismCount = SizeMismatchPane.MAXROWS;
} else if (sizeMismCount > 0){
sizeTitle = "Sizes [" + sizeMismCount + "]";
}
if (sizeMismCount > 0)
compNode.add(new DefaultMutableTreeNode(
new TreeNode(compTreeNode, sizeTitle,
compNdx, -1, TreeNode.SIZES)));
// add "export assertion failures" entry, if necessary
int exportAssrtCount = cm.getExportAssertionFailures().size();
String exportAssrtTitle = null;
if (exportAssrtCount > ExportTable.MAXROWS) {
exportAssrtTitle = "Export Assertions [first " + ExportTable.MAXROWS
+ " of " + exportAssrtCount + "]";
exportAssrtCount = ExportTable.MAXROWS;
} else if (exportAssrtCount > 0) {
exportAssrtTitle = "Export Assertions [" + exportAssrtCount + "]";
}
if (exportAssrtCount > 0)
compNode.add(new DefaultMutableTreeNode(
new TreeNode(compTreeNode, exportAssrtTitle,
compNdx, -1, TreeNode.EXPORT_ASSERTS)));
// add "export network conflicts", if necessary
int exportNetConflictCount = cm.getNetworkExportConflicts().size();
String exportNetConfTitle = null;
if (exportNetConflictCount > ExportTable.MAXROWS) {
exportNetConfTitle = "Export/Global Network Conflicts [first " + ExportTable.MAXROWS
+ " of " + exportNetConflictCount + "]";
exportNetConflictCount = ExportTable.MAXROWS;
} else if (exportNetConflictCount > 0) {
exportNetConfTitle = "Export/Global Network Conflicts [" + exportNetConflictCount + "]";
}
if (exportNetConflictCount > 0)
compNode.add(new DefaultMutableTreeNode(
new TreeNode(compTreeNode, exportNetConfTitle,
compNdx, -1, TreeNode.EXPORT_NET_CONF)));
// add "export characteristics conflicts", if necessary
int exportChrConflictCount = cm.getCharactExportConflicts().size();
String exportChrConfTitle = null;
if (exportChrConflictCount > ExportTable.MAXROWS) {
exportChrConfTitle = "Export/Global Characteristics Conflicts [first "
+ ExportTable.MAXROWS + " of " + exportChrConflictCount + "]";
exportChrConflictCount = ExportTable.MAXROWS;
} else if (exportChrConflictCount > 0) {
exportChrConfTitle = "Export/Global Characteristics Conflicts ["
+ exportChrConflictCount + "]";
}
if (exportChrConflictCount > 0)
compNode.add(new DefaultMutableTreeNode(
new TreeNode(compTreeNode, exportChrConfTitle,
compNdx, -1, TreeNode.EXPORT_CHR_CONF)));
// add "unrecognized Parts", if necessary
int unrecPartsCount = cm.getUnrecognizedParts().size();
String unrecPartsTitle = null;
if (unrecPartsCount > ExportTable.MAXROWS) {
unrecPartsTitle = "Unrecognized Parts [first "
+ ExportTable.MAXROWS + " of " + unrecPartsCount + "]";
unrecPartsCount = ExportTable.MAXROWS;
} else if (unrecPartsCount > 0) {
unrecPartsTitle = "Unrecognized Parts [" + unrecPartsCount + "]";
}
if (unrecPartsCount > 0)
compNode.add(new DefaultMutableTreeNode(
new TreeNode(compTreeNode, unrecPartsTitle,
compNdx, -1, TreeNode.UNRECOG_PART)));
}
setRootVisible(true);
updateUI();
expandRow(0); // expand root
expandRow(1); // expand first comparison
setRootVisible(false); // hide root
addSelectionRow(0); // select first comparison
requestFocusInWindow();
updateInProgress = false;
}
/**
* Add Part equiv. classes nodes
* @param compTreeNode top-level comparison node
* @param compNdx comparison index
* @param inode tree node to add to
* @param mismEqRecs equiv. classes
* @param lpRes results of Local Partitioning
* @param isHashChecked true is hashcodes were checked
*/
private void addPartClasses(TreeNode compTreeNode, int compNdx,
DefaultMutableTreeNode inode,
EquivRecReport[] mismEqRecs,
boolean isHashChecked) {
DefaultMutableTreeNode parts, eclass;
// add parts entry title
TreeNode partsNode = new TreeNode(compTreeNode, "Parts ",
compNdx, -1, TreeNode.TITLE);
parts = new DefaultMutableTreeNode(partsNode);
inode.add(parts);
// add part equivalence classes
int type = TreeNode.PART;
int count=0;
boolean truncated = false;
for (int i=0; i<mismEqRecs.length; i++) {
if (!mismEqRecs[i].hasParts()) continue;
count++;
// limit output size
if (count > MAX_CLASSES) { truncated = true; continue;}
List<String> reasons = mismEqRecs[i].getReasons();
StringBuffer nodeName = new StringBuffer("#"+ count + " [");
int size = mismEqRecs[i].maxSize();
if (size > MAX_LIST_ELEMENTS)
nodeName.append("first " + MAX_LIST_ELEMENTS + " of ");
nodeName.append(size + "]");
Iterator<String> it = null;
String reas = null;
if (! isHashChecked) { // don't process reasons for hash code classes
it = reasons.iterator();
if (it.hasNext()) {
reas = it.next();
// fetch part type if it's available
int ind = reas.indexOf("type is ");
if (ind >= 0) {
nodeName.append(": " + reas.substring(ind + 8));
reas = null;
}
}
if (it.hasNext() || reas != null) {
if (reas == null) {
reas = it.next();
nodeName.append(", ");
} else
nodeName.append(": ");
// fetch number of wires attached if it's available
if (reas.endsWith("different Wires attached")) {
int a = reas.indexOf("has ") + 4;
int b = reas.indexOf(" different");
nodeName.append(reas.substring(a,b) + " Wires attached");
reas = null;
}
}
}
TreeNode partTreeNode = new TreeNode(compTreeNode, nodeName.toString(),
compNdx, i, type);
partTreeNode.setShortName("Part Class #"+ count);
eclass = new DefaultMutableTreeNode(partTreeNode);
parts.add(eclass);
if (! isHashChecked) { // don't process reasons for hash code classes
if (reasons.size() == 0) {
eclass.add(new DefaultMutableTreeNode(
new TreeNode(partTreeNode, "all Parts are indistinguishable",
compNdx, i, TreeNode.PARTLEAF)));
} else {
if (reas != null)
eclass.add(new DefaultMutableTreeNode(
new TreeNode(partTreeNode, reas, compNdx, i, TreeNode.PARTLEAF)));
while (it.hasNext())
eclass.add(new DefaultMutableTreeNode(
new TreeNode(partTreeNode, it.next(),
compNdx, i, TreeNode.PARTLEAF)));
}
}
}
if (count == 0)
inode.remove(parts); // remove "Parts" node if no Part classes exist
else {
StringBuffer buf = new StringBuffer("Parts ");
if (isHashChecked) buf.append("(hash code) ");
buf.append("[");
if (truncated) buf.append("first " + MAX_CLASSES + " of ");
buf.append((count) + "]");
partsNode.setFullName(buf.toString());
}
}
/**
* Add Wire equiv. classes nodes
* @param compTreeNode top-level comparison node
* @param compNdx comparison index
* @param inode tree node to add to
* @param mismEqRecs equiv. classes
* @param lpRes results of Local Partitioning
* @param isHashChecked true is hashcodes were checked
*/
private void addWireClasses(TreeNode compTreeNode, int compNdx,
DefaultMutableTreeNode inode,
EquivRecReport[] mismEqRecs,
boolean isHashChecked) {
DefaultMutableTreeNode wires, eclass, node;
// add wires entry title
TreeNode wiresNode = new TreeNode(compTreeNode, "Wires ",
compNdx, -1, TreeNode.TITLE);
wires = new DefaultMutableTreeNode(wiresNode);
inode.add(wires);
// add wire equivalence classes
TreeNode wireTreeNode;
int type = TreeNode.WIRE;
int count = 0;
boolean truncated = false;
int i=0;
for (; i<mismEqRecs.length; i++) {
if (mismEqRecs[i].hasParts()) continue;
count++;
// limit output size
if (count > MAX_CLASSES) { truncated = true; continue;}
wireTreeNode = new TreeNode(compTreeNode, "Wire Class #" + count,
compNdx, i, type);
wireTreeNode.setShortName("Wire Class #" + count);
wireTreeNode.setWireClassNum(count-1);
eclass = new DefaultMutableTreeNode(wireTreeNode);
wires.add(eclass);
if (!isHashChecked) {
String reasons[] =
mismEqRecs[i].getReasons().toArray(new String[0]);
int j = 0;
if (reasons.length == 0) {
eclass.add(new DefaultMutableTreeNode(
new TreeNode(wireTreeNode, "all Wires are indistinguishable",
compNdx, i, TreeNode.WIRELEAF)));
} else if (reasons.length > 1
&& reasons[0].startsWith("0") && reasons[1].startsWith("0")) {
node = new DefaultMutableTreeNode(
new TreeNode(wireTreeNode, "0's", compNdx, i, TreeNode.WIRELEAF));
eclass.add(node);
for (; j<reasons.length && reasons[j].startsWith("0"); j++) {
if (j >= MAX_ZEROS) continue; // limit number of zeros displayed
int start = reasons[j].indexOf(" of ");
String reason;
if (start >= 0)
reason = reasons[j].substring(start + 4);
else
reason = reasons[j];
node.add(new DefaultMutableTreeNode(
new TreeNode(wireTreeNode, reason, compNdx, i, TreeNode.WIRELEAF)));
}
}
for (; j<reasons.length; j++)
eclass.add(new DefaultMutableTreeNode(
new TreeNode(wireTreeNode, reasons[j], compNdx, i, TreeNode.WIRELEAF)));
}
}
if (count == 0)
inode.remove(wires);
else {
StringBuffer buf = new StringBuffer("Wires ");
if (isHashChecked) buf.append("(hash code) ");
buf.append("[");
if (truncated) buf.append("first " + MAX_CLASSES + " of ");
buf.append((count) + "]");
wiresNode.setFullName(buf.toString());
wireClassNodes[compNdx] = new WireClassNode[count];
}
}
/* (non-Javadoc)
* ActionListener interface (for popup menus)
*/
public void actionPerformed(ActionEvent e) {
Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard();
// copy text prepared during popup to clipboard
StringSelection ss = new StringSelection(clipboard);
cb.setContents(ss,ss);
}
/* (non-Javadoc)
* TreeSelectionListener interface
*/
public void valueChanged(TreeSelectionEvent e) {
TreePath[] paths = e.getPaths();
boolean doAdded = false;
// one pass for removed, one - for added nodes
for (int i=0; i<2; i++) {
// loop over all nodes whose state has changed
for (int j=0; j<paths.length; j++) {
if (e.isAddedPath(j) != doAdded) continue;
if (paths[j] == null) {
parentPane.treeSelectionChanged(null, doAdded);
continue;
}
DefaultMutableTreeNode node = (DefaultMutableTreeNode)paths[j].getLastPathComponent();
// notify Comparison Pane about the change
parentPane.treeSelectionChanged((TreeNode)node.getUserObject(), doAdded);
}
doAdded = true;
}
// update Comparison Pane
parentPane.updateRightPane();
}
private class MyRenderer extends DefaultTreeCellRenderer {
/* (non-Javadoc)
* TreeCellRenderer interface
*/
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean selected, boolean expanded, boolean leaf,
int row, boolean hasFocus) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
TreeNode data = (TreeNode)node.getUserObject();
int compNdx = data.compNdx;
int wclass = data.getWireClassNum();
if (data.type == TreeNode.WIRE && !updateInProgress
&& compNdx < wireClassNodes.length && wireClassNodes[compNdx] != null
&& wclass < wireClassNodes[compNdx].length) {
// wclass is a special index of Wire classes in each comparison
// Needed because Wire and part classes are mixed together
if (wireClassNodes[compNdx][wclass] == null)
createWireClassNodes(data, node.isLeaf());
if (selected)
wireClassNodes[compNdx][wclass].select();
else
wireClassNodes[compNdx][wclass].deselect();
if (!node.isLeaf())
if (expanded)
wireClassNodes[compNdx][wclass].expand();
else
wireClassNodes[compNdx][wclass].collapse();
return wireClassNodes[compNdx][wclass].getPanel();
}
return super.getTreeCellRendererComponent(tree, value, selected, expanded,
leaf, row, hasFocus);
}
}
/**
* Create Wire class nodes for the comparison represented by the supplied node
* @param data comparison top-level tree node
* @param areLeaves true if Wire class nodes are leaves
*/
private void createWireClassNodes(TreeNode data, boolean areLeaves) {
int compNdx = data.compNdx;
EquivRecReport[] mismEqRecs = parentPane.getMismatchEquivRecs(compNdx);
int count = 0, len = wireClassNodes[compNdx].length;
// max width of the first 3 columns in node names, height of a name
int maxWidth0 = 0, maxWidth1 = 0, maxWidth2 = 0, height = 0;
Font font = getFont();
boolean isHashPrinted = mismatches[compNdx].isHashFailuresPrinted();
int i;
if (isHashPrinted)
i = 0;
else // in LP wire mismatches are grouped at the end of mismEqRecs
i = mismatches[compNdx].getPartRecReports().size();
// for each equiv. class
for (; i<mismEqRecs.length; i++) {
if (isHashPrinted && mismEqRecs[i].hasParts())
continue;
count++;
// number of classes might have been limited
if (count > len) break;
// list of mismatched NetObjects
List<List<NetObjReport>> mism = mismEqRecs[i].getNotMatchedNetObjs();
JLabel labels[] = new JLabel[4];
String descr[] = new String[2];
// get names of the first wires in both cells
String instDescr = null;
for (int cell=0; cell < 2; cell++) {
if (mism.get(cell).size() == 0) {
descr[cell] = "{ }";
} else if (mism.get(cell).size() > 0) {
instDescr = mism.get(cell).get(0).instanceDescription();
descr[cell] = createFirstWireOverview(instDescr, (mism.get(cell).size() > 1));
}
}
// create count of Wires in the class
StringBuffer lab3Name = new StringBuffer(24);
lab3Name.append("[");
int size;
if (isHashPrinted)
size = mismEqRecs[i].maxSize();
else
size = Math.max(mism.get(0).size(), mism.get(1).size());
if (size > MAX_LIST_ELEMENTS)
lab3Name.append("first " + MAX_LIST_ELEMENTS + " of ");
lab3Name.append(size + "]");
StringBuffer name = new StringBuffer(32);
// class sequence number
labels[0] = new JLabel("#" + count + " : ");
labels[0].setHorizontalAlignment(SwingConstants.RIGHT);
name.append(labels[0].getText() + " ");
maxWidth0 = Math.max(labels[0].getPreferredSize().width, maxWidth0);
// name of the first Wire from the first Cell
labels[1] = new JLabel(descr[0]);
name.append(descr[0] + " ");
maxWidth1 = Math.max(labels[1].getPreferredSize().width, maxWidth1);
// name of the first Wire from the second Cell
labels[2] = new JLabel(descr[1]);
name.append(descr[1] + " ");
maxWidth2 = Math.max(labels[2].getPreferredSize().width, maxWidth2);
// max size of classes (count)
labels[3] = new JLabel(lab3Name.toString());
name.append(labels[3].getText());
for (int j=0; j<4; j++) {
labels[j].setBorder(border);
labels[j].setFont(font);
}
data.setFullName(name.toString());
wireClassNodes[compNdx][count-1] = new WireClassNode(labels, areLeaves);
if (count == 1) height = labels[0].getPreferredSize().height;
}
// apply the computed dimensions to all Wire class nodes
if (count > 0) {
Dimension dim[] = new Dimension[3];
dim[0] = new Dimension(maxWidth0 , height);
dim[1] = new Dimension(maxWidth1 + 10, height);
dim[2] = new Dimension(maxWidth2 + 10, height);
for (int j=0; j<count; j++)
wireClassNodes[compNdx][j].setTextLabelDimension(dim);
}
}
private String createFirstWireOverview(String instDescr, boolean hasMore) {
// get the name of the first Wire in the class
String descr = parentPane.cleanNetObjectName(instDescr);
int ind = descr.indexOf(" in Cell: ");
if (ind > 0) descr = descr.substring(0, ind).trim();
// limit name length
if (descr.length() > MAX_NAME_LEN)
descr = descr.substring(0, MAX_NAME_LEN) + "...";
// surround name by brackets
if (hasMore) // if more than one Wire belongs to the class
descr = "{ " + descr + ",...}";
else
descr = "{ " + descr + " }";
return descr;
}
/**
* This mouse adapter is used to get right mouse click events and
* trigger the popup menu.
*/
private class TreeMouseAdapter extends MouseAdapter {
public void mousePressed(MouseEvent e) {
if (! (e.getButton() == MouseEvent.BUTTON2
|| e.getButton() == MouseEvent.BUTTON3))
return;
JTree aTree = (JTree)e.getSource();
if (aTree.getRowForLocation(e.getX(), e.getY()) != -1) {
TreePath selPath = aTree.getPathForLocation(e.getX(), e.getY());
DefaultMutableTreeNode node = (DefaultMutableTreeNode)selPath.getLastPathComponent();
TreeNode data = (TreeNode)node.getUserObject();
// extract node name to be copied to clipboard
clipboard = data.toString();
popup.show(e.getComponent(), e.getX(), e.getY());
}
}
}
/**
* This class is a container of a tree node data. Each DefaultMutableTreeNode in
* ComparisonTree has a TreeNode as a data object.
*/
static class TreeNode {
/* --- node types ---*/
public static final int TITLE = 0;
public static final int COMP_TITLE = 1;
public static final int EXPORTS = 2;
public static final int PART = 3;
public static final int WIRE = 4;
public static final int PARTLEAF = 5;
public static final int WIRELEAF = 6;
public static final int SIZES = 7;
public static final int EXPORT_ASSERTS = 8;
public static final int EXPORT_NET_CONF = 9;
public static final int EXPORT_CHR_CONF = 10;
public static final int UNRECOG_PART = 11;
/** comparison index */ public final int compNdx;
/** equiv. class */ public final int eclass;
/** type */ public final int type;
/** parent node */ private TreeNode parent;
/** full name. Used in tree node names */ private String fullName;
/** full name. Used in right pane row names */ private String shortName;
/** If this node represents a wire class, then wireClassNum is the
* index of this class in EquivRecReport array of the corresponding
* NccComparisonResult object. Otherwise is -1. */
private int wireClassNum = -1;
public TreeNode(TreeNode parent, String fullName,
int compNdx, int eclass, int type) {
this.parent = parent;
this.fullName = fullName;
shortName = fullName;
this.compNdx = compNdx;
this.eclass = eclass;
this.type = type;
}
public void setFullName(String n) { fullName = n; }
public void setShortName(String n) { shortName = n;}
/** Only for nodes with type WIRE */
public void setWireClassNum(int num) {
if (type != WIRE) return;
wireClassNum = num;
}
public String getFullName() { return fullName; }
public String getShortName() { return shortName; }
public TreeNode getParent() { return parent; }
public int getWireClassNum() { return wireClassNum; }
public String toString() { return fullName; }
}
/**
* This class encapsulates a Wire class tree node
* Specifically, it encapsulates the panel with labels used as its name
*/
private static class WireClassNode {
/** top-level panel */ private JPanel treeNodePanel;
/** text-only panel */ private JPanel textPanel;
/** icon label */ private JLabel iconLabel;
/** text labels */ private JLabel textLabels[];
/** true if node is leaf */ private boolean isLeaf;
/** true if node is expanded */ private boolean expanded = false;
/** true if node is selected */ private boolean selected = false;
/** true if shared data was initialized */
private static boolean inited = false;
/* --- shared data --- */
private static Color selBackgnd, deselBackgnd, selText, deselText;
private static Icon leafIcon, openIcon, closedIcon;
private static Border border = BorderFactory.createEmptyBorder();
public WireClassNode(JLabel labels[], boolean leaf) {
if (!inited) init();
textLabels = labels;
isLeaf = leaf;
textPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
textPanel.setBorder(border);
textPanel.setBackground(deselBackgnd);
for (int j=0; j<4; j++) textPanel.add(textLabels[j]);
treeNodePanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
treeNodePanel.setBorder(border);
treeNodePanel.setBackground(deselBackgnd);
if (isLeaf)
iconLabel = new JLabel(leafIcon);
else
iconLabel = new JLabel(closedIcon);
iconLabel.setBorder(border);
iconLabel.setText(" ");
treeNodePanel.add(iconLabel);
treeNodePanel.add(textPanel);
}
/**
* Get colors and icons from default renderer
* @param renderer instance of the default tree node renderer
*/
private static void init() {
DefaultTreeCellRenderer defCellRenderer = new DefaultTreeCellRenderer();
selBackgnd = defCellRenderer.getBackgroundSelectionColor();
deselBackgnd = defCellRenderer.getBackgroundNonSelectionColor();
selText = defCellRenderer.getTextSelectionColor();
deselText = defCellRenderer.getTextNonSelectionColor();
leafIcon = defCellRenderer.getDefaultLeafIcon();
openIcon = defCellRenderer.getDefaultOpenIcon();
closedIcon = defCellRenderer.getDefaultClosedIcon();
inited = true;
}
public void select() {
if (selected) return;
textPanel.setBackground(selBackgnd);
for (int i=0; i<4; i++) textLabels[i].setForeground(selText);
selected = true;
}
public void deselect() {
if (!selected) return;
textPanel.setBackground(deselBackgnd);
for (int i=0; i<4; i++) textLabels[i].setForeground(deselText);
selected = false;
}
public void expand() {
if (isLeaf || expanded) return;
iconLabel.setIcon(openIcon);
expanded = true;
}
public void collapse() {
if (isLeaf || !expanded) return;
iconLabel.setIcon(closedIcon);
expanded = false;
}
public void setTextLabelDimension(Dimension[] dim) {
for (int j=0; j<dim.length; j++) {
textLabels[j].setMinimumSize(dim[j]);
textLabels[j].setPreferredSize(dim[j]);
}
}
/**
* Get top-level panel with all labels and icon
* @return the top-level panel to be rendered to a tree node
*/
public JPanel getPanel() { return treeNodePanel; }
}
}