/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: ComparisonsPane.java * * Copyright (c) 2003 Sun Microsystems and Static Free Software * * 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.BorderLayout; import java.awt.Color; import java.awt.Component; 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.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Vector; import javax.swing.BorderFactory; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.border.Border; import javax.swing.tree.DefaultMutableTreeNode; import com.sun.electric.database.hierarchy.Cell; import com.sun.electric.database.text.CellName; import com.sun.electric.database.variable.VarContext; import com.sun.electric.tool.ncc.result.EquivRecReport; import com.sun.electric.tool.ncc.result.NccResult; import com.sun.electric.tool.ncc.result.NetObjReport; import com.sun.electric.tool.ncc.result.PartReport; import com.sun.electric.tool.ncc.result.WireReport; import com.sun.electric.tool.user.Highlighter; import com.sun.electric.tool.user.ncc.ComparisonsTree.TreeNode; /** * This class implements the right side of the NCC GUI window. * It is a placeholder for tables of different types, such as Exports, * Equivalence Classes, Sizes, etc. */ class ComparisonsPane extends JSplitPane implements ActionListener { /* what is currently displayed */ private static final int EMPTY = 0; private static final int COMP_SUMMARY = 1; private static final int EXPORTS = 2; private static final int PARTS_WIRES = 3; private static final int SIZES = 4; private static final int EXPORT_ASSERTS = 5; private static final int EXPORT_NET_CONF = 6; private static final int EXPORT_CHR_CONF = 7; private static final int UNRECOG_PART = 8; /** max number of concurrent equiv. classes */ private static final int MAX_CONCUR_EQ_RECS = 5; private static final String emptyStr = " "; private static final String LSEP = System.getProperty("line.separator"); /* --- GUI variables --- */ protected String defaultTitles[] = {emptyStr, emptyStr}; private String treeTitle = " Mismatched Comparisons"; private JLabel treeLabel = new JLabel(treeTitle); private ComparisonsTree tree; private JScrollPane treeScrollPane; private int dispOnRight = EMPTY; private static Border border = BorderFactory.createEmptyBorder(); /* tables corresponding to different tree node types */ private JScrollPane exportsPanes[]; private JScrollPane exportAssertionsPanes[]; private JScrollPane exportNetConflictPanes[]; private JScrollPane exportChrConflictPanes[]; private JScrollPane unrecognizedPartsPanes[]; private EquivClassSplitPane rightSplPanes[]; private JPanel sizesPanes[]; /** Right-click popup for a tree node */ protected JPopupMenu treePopup; /** Right-click popup for a table cell */ protected JPopupMenu cellPopup; protected String clipboard; /* --- Data holders --- */ /** Current list of mismatched comparisons */ private NccGuiInfo mismatches[]; /** Current list of Wire/Part equiv. classes with mismatches */ private EquivRecReport mismEqRecs[][]; /** Mismatched NetObjects in current EquivRecords */ private List<NetObjReport>[] mismNetObjs[][]; /** Matched NetObjects in current EquivRecords */ private List<NetObjReport>[] matchedNetObjs[][]; /** Vector of currently selected equiv. class TreeNode objects */ private Vector<TreeNode> curEqRecNodes = new Vector<TreeNode>(); /** Vector of equiv. class TreeNode objects that should be displayed */ private Vector<TreeNode> curEqRecNodesToDisplay = new Vector<TreeNode>(); /** Vector of currently selected exclusive TreeNode objects Exclusive nodes are those requiring exclusive access to the right pane. All nodes except for EquivRecord and TITLE are exclusive. */ private Vector<TreeNode> curExlusiveNodes = new Vector<TreeNode>(); public ComparisonsPane() { super(JSplitPane.HORIZONTAL_SPLIT); setOneTouchExpandable(true); setDividerLocation(0.5); // after a resize the right half gets more resized setResizeWeight(0.2); createCellPopup(); rightSplPanes = new EquivClassSplitPane[MAX_CONCUR_EQ_RECS]; for (int i=0; i<MAX_CONCUR_EQ_RECS; i++) rightSplPanes[i] = new EquivClassSplitPane(this, i+1); setRightComponent(rightSplPanes[0]); JPanel leftPanel = new JPanel(new BorderLayout()); leftPanel.add(treeLabel, BorderLayout.NORTH); leftPanel.setBorder(border); TreeNode rootNode = new TreeNode(null, treeTitle, -1, -1, TreeNode.TITLE); tree = new ComparisonsTree(this, new DefaultMutableTreeNode(rootNode)); treeScrollPane = new JScrollPane(tree); leftPanel.add(treeScrollPane, BorderLayout.CENTER); setLeftComponent(leftPanel); } /** Set the current set of mismatches to the provided one */ public void setMismatches(List<NccGuiInfo> misms) { mismatches = misms.toArray(new NccGuiInfo[0]); // allocate arrays of for tables mismEqRecs = new EquivRecReport[mismatches.length][]; mismNetObjs = new ArrayList[mismatches.length][][]; matchedNetObjs = new ArrayList[mismatches.length][][]; exportsPanes = new JScrollPane[mismatches.length]; exportAssertionsPanes = new JScrollPane[mismatches.length]; exportNetConflictPanes = new JScrollPane[mismatches.length]; exportChrConflictPanes = new JScrollPane[mismatches.length]; unrecognizedPartsPanes = new JScrollPane[mismatches.length]; sizesPanes = new JPanel[mismatches.length]; // clear lists of selected/displayed TreeNode objects curEqRecNodes.clear(); curEqRecNodesToDisplay.clear(); curExlusiveNodes.clear(); // display summary of the first comparison int divPos = getDividerLocation(); dispOnRight = COMP_SUMMARY; displayComparisonSummary(0); setDividerLocation(divPos); // update tree StringBuffer buf = new StringBuffer(treeTitle + " ["); if (mismatches.length > ComparisonsTree.MAX_COMP_NODES) buf.append("first " + ComparisonsTree.MAX_COMP_NODES + " of "); buf.append(mismatches.length + "]"); treeLabel.setText(buf.toString()); tree.update(mismatches); treeScrollPane.getVerticalScrollBar().setValue(0); getExportsPane(0); // preload exports of the first comparison } /** * Set the array of Part/Wire equiv. classes for comparison number compNdx * @param compNdx index of the comparison * @param equivRecs array of equiv. classes */ protected void setMismatchEquivRecs(int compNdx, EquivRecReport[] equivRecs) { mismEqRecs[compNdx] = equivRecs; mismNetObjs[compNdx] = new ArrayList[equivRecs.length][]; matchedNetObjs[compNdx] = new ArrayList[equivRecs.length][]; } /** * Get the array of Part/Wire equiv. classes for comparison number compNdx * @param compNdx index of the comparison * @return array of equiv. classes */ protected EquivRecReport[] getMismatchEquivRecs(int compNdx) { return mismEqRecs[compNdx]; } /** * Reset the content of the right pane to empty */ private void resetRightPane() { // reset right pane view int divPos = getDividerLocation(); for (int j=0; j<2; j++) { rightSplPanes[0].setLabelText(0,j,defaultTitles[j]); rightSplPanes[0].setCellText(0,j,emptyStr); } setRightComponent(rightSplPanes[0]); setDividerLocation(divPos); dispOnRight = EMPTY; } /** * Get the Exports table for comparison number compNdx * @param compNdx comparison index * @return Exports table wrapped into a JScrollPane */ private JScrollPane getExportsPane(int compNdx) { if (compNdx < 0 || compNdx >= exportsPanes.length) return null; if (exportsPanes[compNdx] == null) { ExportMismatchTable table = new ExportMismatchTable(mismatches[compNdx]); exportsPanes[compNdx] = new JScrollPane(table); exportsPanes[compNdx].setBackground(Color.WHITE); } return exportsPanes[compNdx]; } /** * Get the Export Assertions table for comparison number compNdx * @param compNdx comparison index * @return Export Assertions table wrapped into a JScrollPane */ private JScrollPane getExportAssertionPane(int compNdx) { if (compNdx < 0 || compNdx >= exportAssertionsPanes.length) return null; if (exportAssertionsPanes[compNdx] == null) { ExportAssertionTable table = new ExportAssertionTable(mismatches[compNdx]); exportAssertionsPanes[compNdx] = new JScrollPane(table); exportAssertionsPanes[compNdx].setBackground(Color.WHITE); } return exportAssertionsPanes[compNdx]; } /** * Get the Export/Global Network Conflict table for comparison number compNdx * @param compNdx comparison index * @return Export/Global Network Conflict table wrapped into a JScrollPane */ private JScrollPane getExportNetConflictPane(int compNdx) { if (compNdx < 0 || compNdx >= exportNetConflictPanes.length) return null; if (exportNetConflictPanes[compNdx] == null) { ExportConflictTable table = new ExportConflictTable.NetworkTable(mismatches[compNdx]); exportNetConflictPanes[compNdx] = new JScrollPane(table); exportNetConflictPanes[compNdx].setBackground(Color.WHITE); } return exportNetConflictPanes[compNdx]; } /** * Get the Export/Global Characteristics Conflict table for comparison number compNdx * @param compNdx comparison index * @return Export/Global Characteristics Conflict table wrapped into a JScrollPane */ private JScrollPane getExportChrConflictPane(int compNdx) { if (compNdx < 0 || compNdx >= exportChrConflictPanes.length) return null; if (exportChrConflictPanes[compNdx] == null) { ExportConflictTable table = new ExportConflictTable.CharacteristicsTable(mismatches[compNdx]); exportChrConflictPanes[compNdx] = new JScrollPane(table); exportChrConflictPanes[compNdx].setBackground(Color.WHITE); } return exportChrConflictPanes[compNdx]; } /** * Get the Unrecognized Parts table for comparison number compNdx * @param compNdx comparison index * @return Unrecognized Parts table wrapped into a JScrollPane */ private JScrollPane getUnrecognizedPartsPane(int compNdx) { if (compNdx < 0 || compNdx >= unrecognizedPartsPanes.length) return null; if (unrecognizedPartsPanes[compNdx] == null) { UnrecognizedPartTable table = new UnrecognizedPartTable(mismatches[compNdx]); unrecognizedPartsPanes[compNdx] = new JScrollPane(table); unrecognizedPartsPanes[compNdx].setBackground(Color.WHITE); } return unrecognizedPartsPanes[compNdx]; } /** * Get the Sizes table for comparison number compNdx * @param compNdx comparison index * @return Sizes table wrapped into a JScrollPane */ private JPanel getSizesPane(int compNdx) { if (compNdx < 0 || compNdx >= sizesPanes.length) return null; if (sizesPanes[compNdx] == null) sizesPanes[compNdx] = new SizeMismatchPane(mismatches[compNdx]); return sizesPanes[compNdx]; } /** * Notify Comparisons Pane that the tree selection has changed. The supplied * TreeNode was either added (added is true) or removed (added is false) * from the current selection * @param node a TreeNode whose state has changed * @param added true if the node was added, false otherwise */ public void treeSelectionChanged(TreeNode node, boolean added) { if (node == null) return; int type = node.type; if (type == TreeNode.TITLE) return; if (type == TreeNode.PARTLEAF || type == TreeNode.WIRELEAF) { node = node.getParent(); type = node.type; } if (!added) { // if node is removed from selection if (type == TreeNode.PART || type == TreeNode.WIRE) curEqRecNodes.remove(node); else curExlusiveNodes.remove(node); } else { // if node is added to selection if (type == TreeNode.PART || type == TreeNode.WIRE) curEqRecNodes.add(node); else curExlusiveNodes.add(node); } } /** * Update right pane. Content of the pane depends on the current tree selection * and should be updated every time the selection changes. */ public void updateRightPane() { int divPos = getDividerLocation(); if (curExlusiveNodes.size() > 0) { // if an exclusive node is selected // get the first node (it is selected for the longest time) TreeNode exNode = curExlusiveNodes.firstElement(); int exType = exNode.type; switch (exType) { case TreeNode.COMP_TITLE: dispOnRight = COMP_SUMMARY; displayComparisonSummary(exNode.compNdx); break; case TreeNode.EXPORTS: dispOnRight = EXPORTS; setRightComponent(getExportsPane(exNode.compNdx)); break; case TreeNode.SIZES: dispOnRight = SIZES; setRightComponent(getSizesPane(exNode.compNdx)); break; case TreeNode.EXPORT_ASSERTS: dispOnRight = EXPORT_ASSERTS; setRightComponent(getExportAssertionPane(exNode.compNdx)); break; case TreeNode.EXPORT_NET_CONF: dispOnRight = EXPORT_NET_CONF; setRightComponent(getExportNetConflictPane(exNode.compNdx)); break; case TreeNode.EXPORT_CHR_CONF: dispOnRight = EXPORT_CHR_CONF; setRightComponent(getExportChrConflictPane(exNode.compNdx)); break; case TreeNode.UNRECOG_PART: dispOnRight = UNRECOG_PART; setRightComponent(getUnrecognizedPartsPane(exNode.compNdx)); break; } setDividerLocation(divPos); // restore divider position return; } else if (curEqRecNodes.size() == 0) { // if no equiv. class is selected resetRightPane(); // display an empty right pane return; } // the right pane will display one or more equiv. classes dispOnRight = PARTS_WIRES; // get equiv. classes to be displayed curEqRecNodesToDisplay.clear(); int i = 0; for (Iterator<TreeNode> it=curEqRecNodes.iterator(); it.hasNext() && i<MAX_CONCUR_EQ_RECS;) { TreeNode eqRecNode = it.next(); if (curEqRecNodesToDisplay.contains(eqRecNode)) continue; // skip if already displayed curEqRecNodesToDisplay.add(eqRecNode); i++; } // get a pane with proper number of rows EquivClassSplitPane rightSplPane = rightSplPanes[curEqRecNodesToDisplay.size()-1]; i = 0; // fill pane with data row by row for (Iterator<TreeNode> it=curEqRecNodesToDisplay.iterator(); it.hasNext(); i++) { TreeNode eqRecNode = it.next(); String partitionTitle = eqRecNode.getParent().getShortName() + " : " + eqRecNode.getShortName(); rightSplPane.setPartitionTitle(i, partitionTitle); List<NetObjReport>[] mism = new ArrayList[2]; EquivRecReport eqRec = mismEqRecs[eqRecNode.compNdx][eqRecNode.eclass]; mism[0] = eqRec.getNotMatchedNetObjs().get(0); mism[1] = eqRec.getNotMatchedNetObjs().get(1); mismNetObjs[eqRecNode.compNdx][eqRecNode.eclass] = mism; List<NetObjReport>[] matched = new ArrayList[2]; matched[0] = eqRec.getMatchedNetObjs().get(0); matched[1] = eqRec.getMatchedNetObjs().get(1); matchedNetObjs[eqRecNode.compNdx][eqRecNode.eclass] = matched; // if (mismatches[eqRecNode.compNdx].isHashFailuresPrinted()) // fillHashPartitionResults(eqRecNode, rightSplPane, i); // else fillLocalPartitionResults(eqRecNode, rightSplPane, i); } setRightComponent(rightSplPane); setDividerLocation(divPos); rightSplPane.updateLayout(); } /** * Fill the provided split cell with parts or wires from compared cells that * belong to the local partitioning equivalence class identified by * the provided tree node. * @param node tree node * @param pane split pane * @param row row in the split pane (>1 rows if >1 node selected) */ private void fillLocalPartitionResults(TreeNode node, EquivClassSplitPane pane, int row) { int swap = 0; if (mismatches[node.compNdx].isSwapCells()) swap = 1; List<NetObjReport>[] matched = matchedNetObjs[node.compNdx][node.eclass]; List<NetObjReport>[] mism = mismNetObjs[node.compNdx][node.eclass]; String href = "<a style=\"text-decoration: none\" href=\""; StringBuffer html = new StringBuffer(256); for (int cell=0; cell<2; cell++) { int ndx = (cell + swap)%2; StringBuffer curCellText = pane.getCellPlainTextBuffer(row,ndx); curCellText.setLength(0); html.setLength(0); // fonts: Courier, Dialog, Helvetica, TimesRoman, Serif html.append("<html><FONT SIZE=3><FONT FACE=\"Helvetica, TimesRoman\">"); // mismatched netobjects (printed in red) if (mism[ndx].size() > 0) { html.append("<font COLOR=\"red\">"); for (int k=0; k<mism[ndx].size() && k<ComparisonsTree.MAX_LIST_ELEMENTS; k++) { String descr = cleanNetObjectName( (mism[ndx].get(k)).instanceDescription()); html.append(href + (row*100000 + ndx*10000 + k) +"\">"+ descr + "</a>"); curCellText.append(descr); html.append("<br>"); curCellText.append(LSEP); } html.append("</font>"); } // if this cell has fewer mismatches than the other one // and matches are going to printed in this cell, then add empty lines int sizeDiff = mism[(ndx+1)%2].size() - mism[ndx].size(); if (matched[ndx].size() > 0) while (sizeDiff-- > 0) { html.append("<br>"); curCellText.append(LSEP); } // matched netobjects (printed in green) if (matched[ndx].size() > 0) { html.append("<font COLOR=\"green\">"); for (int k=0; k<matched[ndx].size() && k<ComparisonsTree.MAX_LIST_ELEMENTS; k++) { String descr = cleanNetObjectName( (matched[ndx].get(k)).instanceDescription()); html.append(href + (row*100000 + ndx*10000 + (mism[ndx].size()+k)) + "\">"+ descr + "</a>"); curCellText.append(descr); html.append("<br>"); curCellText.append(LSEP); } html.append("</font>"); } int len = mism[ndx].size() + matched[ndx].size(); // if nothing was printed, then print "none" if (len == 0) { html.append("<b>none</b>"); curCellText.append("none"); } html.append("</font></html>"); pane.setCellText(row,ndx,html.toString()); String title = mismatches[node.compNdx].getNames()[ndx]; if (node.type == TreeNode.WIRE) pane.setLabelText(row,ndx, " "+ len +" Wire(s) in " + title); else pane.setLabelText(row,ndx, " "+ len +" Part(s) in " + title); } } // /** // * Fill the provided split cell with parts or wires from compared cells that // * belong to the hashcode equivalence class identified by the provided tree node. // * @param node tree node // * @param pane split pane // * @param row row in the split pane (>1 rows if >1 node selected) // */ // private void fillHashPartitionResults(TreeNode node, EquivClassSplitPane pane, int row) { // int swap = 0; // if (mismatches[node.compNdx].isSwapCells()) swap = 1; // EquivRecReport eqRec = mismEqRecs[node.compNdx][node.eclass]; // // String href = "<a style=\"text-decoration: none\" href=\""; // StringBuffer html = new StringBuffer(256); // int cell = 0; // for (List<NetObjReport> ckt : eqRec.getNotMatchedNetObjs()) { // int ndx = (cell + swap)%2; // StringBuffer curCellText = pane.getCellPlainTextBuffer(row,ndx); // curCellText.setLength(0); // html.setLength(0); // // fonts: Courier, Dialog, Helvetica, TimesRoman, Serif // html.append("<html><FONT SIZE=3><FONT FACE=\"Helvetica, TimesRoman\">"); // // int len = ckt.size(); // int k=0; // for (NetObjReport r : ckt) { // if (k>=ComparisonsTree.MAX_LIST_ELEMENTS) break; // String descr = cleanNetObjectName(r.instanceDescription()); // // html.append(href + (row*100000 + cell*10000 + k) +"\">"+ descr + "</a>"); // curCellText.append(descr); // html.append("<br>"); // curCellText.append(LSEP); // k++; // } // if (len == 0) { // html.append("<b>none</b>"); // curCellText.append("none"); // } // // html.append("</font></html>"); // pane.setCellText(row,ndx,html.toString()); // // String title = mismatches[node.compNdx].getNames()[ndx]; // if (node.type == TreeNode.WIRE) // pane.setLabelText(row,ndx, " "+ len +" Wire(s) in " + title); // else // pane.setLabelText(row,ndx, " "+ len +" Part(s) in " + title); // } // cell++; // } /** * Display number of parts, wires, ports in the cells in comparison * number compNdx * @param compNdx comparison index */ private void displayComparisonSummary(int compNdx) { EquivClassSplitPane rightSplPane = rightSplPanes[0]; Cell cells[] = mismatches[compNdx].getCells(); NccResult.CellSummary summary = mismatches[compNdx].getCellSummary(); StringBuffer html = new StringBuffer(256); int swap = 0; if (mismatches[compNdx].isSwapCells()) swap = 1; for (int i=0; i<2; i++) { int ndx = (i + swap)%2; StringBuffer curCellText = rightSplPane.getCellPlainTextBuffer(0,ndx); curCellText.setLength(0); html.setLength(0); html.append("<html><FONT SIZE=3><FONT FACE=\"Helvetica, TimesRoman\">"); if (summary.cantBuildNetlist[ndx]) { html.append(/*" Can't build netlist!<br>" +*/ " See problems listed<br>in tree pane.<br>(left most pane). "); curCellText.append(/*" Can't build netlist!" + LSEP + */ " See problems listed"+LSEP+"in tree pane."+LSEP+"(left most pane). "); } else { html.append(summary.numParts[ndx] + " Parts<br>" + summary.numWires[ndx] + " Wires<br>" + summary.numPorts[ndx] + " Ports<br>"); curCellText.append(summary.numParts[ndx] + " Parts" + LSEP + summary.numWires[ndx] + " Wires" + LSEP + summary.numPorts[ndx] + " Ports"); } html.append("</font></html>"); rightSplPane.setCellText(0, ndx, html.toString()); CellName cellName = cells[i].getCellName(); String name = " Summary of " + cellName.getName() + " " + cellName.getView().getAbbreviationExtension(); rightSplPane.setLabelText(0, ndx, name); } setRightComponent(rightSplPane); } /** * Follow hyperlink with the given index and highlight required items * @param index hyperlink index */ void highlight(int index) { int recNdx = index/100000; int cellNdx = (index/10000)%10; int line = index%10000; TreeNode eqRecNode = curEqRecNodesToDisplay.elementAt(recNdx); // in case of hashcode partitions, get NetObject from Circuits NetObjReport partOrWire = null; // if (mismatches[eqRecNode.compNdx].isHashFailuresPrinted()) { // EquivRecReport eqRec = mismEqRecs[eqRecNode.compNdx][eqRecNode.eclass]; // int c = 0, k = 0; // Circuit ckt = null; // for (Iterator<Circuit> it=eqRec.getCircuits(); it.hasNext(); c++, it.next()) // if (c == cellNdx) { // ckt = it.next(); // break; // } // for (Iterator<NetObjReport> it=ckt.getNetObjs(); it.hasNext(); k++, it.next()) // if (k == line) { // partOrWire = it.next(); // break; // } // } else { // in case of LP, get the NetObjeect from the array List<NetObjReport>[] mism = mismNetObjs[eqRecNode.compNdx][eqRecNode.eclass]; List<NetObjReport>[] matched = matchedNetObjs[eqRecNode.compNdx][eqRecNode.eclass]; if (line >= mism[cellNdx].size()) partOrWire = matched[cellNdx].get(line - mism[cellNdx].size()); else partOrWire = mism[cellNdx].get(line); // } Cell cell = null; VarContext context = null; if (partOrWire instanceof PartReport) { cell = ((PartReport)partOrWire).getNameProxy().leafCell(); context = ((PartReport)partOrWire).getNameProxy().getContext(); } else if (partOrWire instanceof WireReport) { cell = ((WireReport)partOrWire).getNameProxy().leafCell(); context = ((WireReport)partOrWire).getNameProxy().getContext(); } // find the highlighter corresponding to the cell Highlighter highlighter = HighlightTools.getHighlighter(cell, context); if (highlighter == null) return; if (partOrWire instanceof PartReport) HighlightTools.highlightPart(highlighter, cell, (PartReport)partOrWire); else if (partOrWire instanceof WireReport) HighlightTools.highlightWire(highlighter, cell, (WireReport)partOrWire); highlighter.finished(); } /** * Remove unnecessary parts from a NetObject name * @param descr NetObject name * @return cleaned name */ public String cleanNetObjectName(String descr) { // drop "Part:" or "Wire:" prefices if (descr.startsWith("Wire: ") || descr.startsWith("Part: ")) descr = descr.substring(6); // drop "Cell instance:" info int ind = descr.indexOf(" Cell instance:"); if (ind > 0) descr = descr.substring(0, ind).trim(); // drop {sch} or {lay} suffices if (descr.endsWith("{sch}") || descr.endsWith("{lay}")) descr = descr.substring(0, descr.length()-5); return descr; } /* (non-Javadoc) * Action Listener 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); } /** * Initialize popup menu for table cells */ private void createCellPopup() { cellPopup = new JPopupMenu(); JMenuItem menuItem = new JMenuItem("Copy Cell Text To Clipboard"); menuItem.addActionListener(this); cellPopup.add(menuItem); } /** * Display a cell popup on top of Component c, with origin at (x,y) * in component's coord system * @param text The text to be copied to clipboard if menu item is activated * @param c Component to place the popup menu on top of * @param x x origin coordinate (in component coord system) * @param y y origin coordinate (in component coord system) */ void showCellPopup(String text, Component c, int x, int y) { clipboard = text; cellPopup.show(c,x,y); } }