/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: Change.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.dialogs; import com.sun.electric.Main; import com.sun.electric.database.EditingPreferences; import com.sun.electric.database.geometry.GenMath.MutableInteger; import com.sun.electric.database.hierarchy.Cell; import com.sun.electric.database.hierarchy.Export; import com.sun.electric.database.hierarchy.Library; import com.sun.electric.database.hierarchy.View; import com.sun.electric.database.network.Netlist; import com.sun.electric.database.prototype.NodeProto; import com.sun.electric.database.prototype.PortProto; import com.sun.electric.database.topology.ArcInst; import com.sun.electric.database.topology.Connection; import com.sun.electric.database.topology.Geometric; import com.sun.electric.database.topology.NodeInst; import com.sun.electric.database.topology.PortInst; import com.sun.electric.technology.ArcProto; import com.sun.electric.technology.PrimitiveNode; import com.sun.electric.technology.PrimitivePort; import com.sun.electric.technology.SizeOffset; import com.sun.electric.technology.Technology; import com.sun.electric.technology.PrimitiveNode.Function; import com.sun.electric.technology.technologies.Generic; import com.sun.electric.technology.technologies.Schematics; import com.sun.electric.tool.Client; import com.sun.electric.tool.Job; import com.sun.electric.tool.JobException; import com.sun.electric.tool.user.CircuitChangeJobs; import com.sun.electric.tool.user.HighlightListener; import com.sun.electric.tool.user.Highlighter; import com.sun.electric.tool.user.User; import com.sun.electric.tool.user.ui.EditWindow; import com.sun.electric.tool.user.ui.ExplorerTree; import com.sun.electric.tool.user.ui.WindowFrame; import java.awt.Frame; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JRadioButton; import javax.swing.JTree; import javax.swing.SwingUtilities; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreePath; /** * Class to handle the "Change" dialog. */ public class Change extends EModelessDialog implements HighlightListener { private static final long serialVersionUID = 1L; /** Change selected only. */ private static final int CHANGE_SELECTED = 1; /** Change all connected to this. */ private static final int CHANGE_CONNECTED = 2; /** Change all in this cell. */ private static final int CHANGE_CELL = 3; /** Change all in this Library. */ private static final int CHANGE_LIBRARY = 4; /** Change all in all Libraries. */ private static final int CHANGE_EVERYWHERE = 5; private static Change theDialog = null; private static boolean lastChangeNodesWithArcs = false; private static boolean lastIgnorePortNames = false; private static boolean lastAllowMissingPorts = false; private static int whatToChange = CHANGE_SELECTED; private static String libSelected = null; private static Map<PrimitiveNode,Map<Function,String>> specialSchematics = null; private DefaultMutableTreeNode rootNode, rootCells, rootPrims, rootArcs, currentlySelected; private DefaultTreeModel treeModel; private JTree changeTree; private List<Geometric> geomsToChange; // List of Geometrics to change private Map<DefaultMutableTreeNode,NodeProto> changeNodeProtoList; private Map<DefaultMutableTreeNode,ArcProto> changeArcProtoList; private Map<DefaultMutableTreeNode,Function> changeNodeProtoFunctionList; private EditWindow wnd; public static void showChangeDialog() { if (Client.getOperatingSystem() == Client.OS.UNIX && theDialog != null) { // On Linux, if a dialog is built, closed using setVisible(false), // and then requested again using setVisible(true), it does // not appear on top. I've tried using toFront(), requestFocus(), // but none of that works. Instead, I brute force it and // rebuild the dialog from scratch each time. theDialog.closeDialog(null); } if (theDialog == null) { JFrame jf = null; jf = (JFrame) Main.getCurrentJFrame(); theDialog = new Change(jf); } theDialog.loadInfo(true); theDialog.setVisible(true); theDialog.toFront(); } private void setupSpecialPrimitives() { if (specialSchematics != null) return; specialSchematics = new HashMap<PrimitiveNode,Map<Function,String>>(); Map<Function,String> specialTransistor = new HashMap<Function,String>(); Map<Function,String> special4Transistor = new HashMap<Function,String>(); List<Function> functions = Function.getFunctions(); for(Function fun : functions) { if (!fun.isTransistor()) continue; Function altFun = fun.make3PortTransistor(); if (altFun != null) special4Transistor.put(fun, fun.getShortName()); else specialTransistor.put(fun, fun.getShortName()); } specialSchematics.put(Schematics.tech().transistorNode, specialTransistor); specialSchematics.put(Schematics.tech().transistor4Node, special4Transistor); Map<Function,String> specialResistor = new HashMap<Function,String>(); specialResistor.put(Function.RESIST, "normal"); specialResistor.put(Function.RESNPOLY, "n-poly"); specialResistor.put(Function.RESPPOLY, "p-poly"); specialResistor.put(Function.RESNNSPOLY, "n-poly-no-silicide"); specialResistor.put(Function.RESPNSPOLY, "p-poly-no-silicide"); specialResistor.put(Function.RESNWELL, "n-well"); specialResistor.put(Function.RESPWELL, "p-well"); specialResistor.put(Function.RESNACTIVE, "n-active"); specialResistor.put(Function.RESPACTIVE, "p-active"); specialResistor.put(Function.RESHIRESPOLY2, "hi-res-poly-2"); specialSchematics.put(Schematics.tech().resistorNode, specialResistor); Map<Function,String> specialDiode = new HashMap<Function,String>(); specialDiode.put(Function.DIODE, "normal"); specialDiode.put(Function.DIODEZ, "zener"); specialSchematics.put(Schematics.tech().diodeNode, specialDiode); Map<Function,String> specialCapacitor = new HashMap<Function,String>(); specialCapacitor.put(Function.CAPAC, "normal"); specialCapacitor.put(Function.ECAPAC, "electrolytic"); specialCapacitor.put(Function.POLY2CAPAC, "poly-2"); specialSchematics.put(Schematics.tech().capacitorNode, specialCapacitor); Map<Function,String> specialFlipFlop = new HashMap<Function,String>(); specialFlipFlop.put(Function.FLIPFLOPRSMS, "RS-ms"); specialFlipFlop.put(Function.FLIPFLOPRSP, "RS-p"); specialFlipFlop.put(Function.FLIPFLOPRSN, "RS-n"); specialFlipFlop.put(Function.FLIPFLOPJKMS, "JK-ms"); specialFlipFlop.put(Function.FLIPFLOPJKP, "JK-p"); specialFlipFlop.put(Function.FLIPFLOPJKN, "JK-n"); specialFlipFlop.put(Function.FLIPFLOPDMS, "D-ms"); specialFlipFlop.put(Function.FLIPFLOPDP, "D-p"); specialFlipFlop.put(Function.FLIPFLOPDN, "D-n"); specialFlipFlop.put(Function.FLIPFLOPTMS, "T-ms"); specialFlipFlop.put(Function.FLIPFLOPTP, "T-p"); specialFlipFlop.put(Function.FLIPFLOPTN, "T-n"); specialSchematics.put(Schematics.tech().flipflopNode, specialFlipFlop); Map<Function,String> specialTwoport = new HashMap<Function,String>(); specialTwoport.put(Function.VCCS, Function.VCCS.getShortName()); specialTwoport.put(Function.CCVS, Function.CCVS.getShortName()); specialTwoport.put(Function.VCVS, Function.VCVS.getShortName()); specialTwoport.put(Function.CCCS, Function.CCCS.getShortName()); specialTwoport.put(Function.TLINE, "transmission"); specialSchematics.put(Schematics.tech().twoportNode, specialTwoport); } /** Creates new form Change */ private Change(Frame parent) { super(parent, false); initComponents(); getRootPane().setDefaultButton(done); apply.setMnemonic('A'); done.setMnemonic('D'); // make sure special primitive map is built setupSpecialPrimitives(); // build the change list currentlySelected = null; rootNode = new DefaultMutableTreeNode(""); rootCells = new DefaultMutableTreeNode("Cells"); rootPrims = new DefaultMutableTreeNode("Primitives"); rootArcs = new DefaultMutableTreeNode("Arcs"); rootNode.add(rootCells); rootNode.add(rootPrims); rootNode.add(rootArcs); treeModel = new MyDefaultTreeModel(rootNode); changeTree = new JTree(treeModel); changeTree.setRootVisible(false); changeTree.setShowsRootHandles(true); changeTree.addMouseListener(new TreeHandler()); listPane.setViewportView(changeTree); changeNodeProtoList = new HashMap<DefaultMutableTreeNode,NodeProto>(); changeArcProtoList = new HashMap<DefaultMutableTreeNode,ArcProto>(); changeNodeProtoFunctionList = new HashMap<DefaultMutableTreeNode,Function>(); // make a popup of libraries List<Library> libList = Library.getVisibleLibraries(); int curIndex = libList.indexOf(Library.getCurrent()); for(Library lib: libList) { librariesPopup.addItem(lib.getName()); if (lib.getName().equals(libSelected)) { curIndex = -1; // won't set to current library now librariesPopup.setSelectedItem(libSelected); } } if (curIndex >= 0) librariesPopup.setSelectedIndex(curIndex); librariesPopup.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { reload(false); } }); // restore defaults ignorePortNames.setSelected(lastIgnorePortNames); allowMissingPorts.setSelected(lastAllowMissingPorts); ignorePortNames.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { rememberState(); } }); allowMissingPorts.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { rememberState(); } }); showPrimitives.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { reload(false); } }); showCells.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { reload(false); } }); changeNodesWithArcs.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { reload(false); } }); // setup the radio buttons that select what to change changeSelected.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { whatToChangeChanged(evt); } }); changeConnected.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { whatToChangeChanged(evt); } }); changeInCell.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { whatToChangeChanged(evt); } }); changeInLibrary.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { whatToChangeChanged(evt); } }); changeEverywhere.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { whatToChangeChanged(evt); } }); switch (whatToChange) { case CHANGE_SELECTED: changeSelected.setSelected(true); break; case CHANGE_CONNECTED: changeConnected.setSelected(true); break; case CHANGE_CELL: changeInCell.setSelected(true); break; case CHANGE_LIBRARY: changeInLibrary.setSelected(true); break; case CHANGE_EVERYWHERE: changeEverywhere.setSelected(true); break; } finishInitialization(); Highlighter.addHighlightListener(this); } /** * Class to handle clicks in the tree. * Tracks what is selected and handles double-clicks to make a change. */ private class TreeHandler implements MouseListener { public void mouseClicked(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} public void mouseReleased(MouseEvent e) {} public void mousePressed(MouseEvent e) { if (e.getClickCount() == 2) { apply(null); return; } currentlySelected = null; TreePath currentPath = changeTree.getPathForLocation(e.getX(), e.getY()); if (currentPath == null) return; currentlySelected = (DefaultMutableTreeNode)currentPath.getLastPathComponent(); } } /** * Class to manage the tree model so that the arcs/cells/primitives are all folder icons. */ private class MyDefaultTreeModel extends DefaultTreeModel { private static final long serialVersionUID = 1L; MyDefaultTreeModel(DefaultMutableTreeNode dmtn) { super(dmtn); } public boolean isLeaf(Object node) { if (node == rootArcs || node == rootCells || node == rootPrims) return false; return super.isLeaf(node); } } /** * Reloads the dialog when Highlights change */ public void highlightChanged(Highlighter which) { if (!isVisible()) return; loadInfo(true); } /** * Called when by a Highlighter when it loses focus. The argument * is the Highlighter that has gained focus (may be null). * @param highlighterGainedFocus the highlighter for the current window (may be null). */ public void highlighterLostFocus(Highlighter highlighterGainedFocus) { if (!isVisible()) return; loadInfo(false); } protected void escapePressed() { done(null); } private void whatToChangeChanged(ActionEvent evt) { JRadioButton src = (JRadioButton)evt.getSource(); if (src == changeSelected) whatToChange = CHANGE_SELECTED; else if (src == changeConnected) whatToChange = CHANGE_CONNECTED; else if (src == changeInCell) whatToChange = CHANGE_CELL; else if (src == changeInLibrary) whatToChange = CHANGE_LIBRARY; else if (src == changeEverywhere) whatToChange = CHANGE_EVERYWHERE; Geometric geomToChange = geomsToChange.get(0); if (whatToChange == CHANGE_EVERYWHERE) { if (geomToChange instanceof ArcInst) { if (changeNodesWithArcs.isSelected()) { changeNodesWithArcs.setSelected(false); reload(false); } changeNodesWithArcs.setEnabled(false); } } else { if (geomToChange instanceof ArcInst) changeNodesWithArcs.setEnabled(true); } updateChangeCount(); } /** * Method to count the number of arcs that will be considered when changing arc "oldAi". * @param connected true to, replace all such arcs connected to this. * @param thiscell true to replace all such arcs in the cell. */ private void countAllArcs(Cell cell, List<Geometric> highs, ArcInst oldAi, boolean connected, boolean thiscell, Set<Geometric> changedAlready) { List<NodeInst> changePins = new ArrayList<NodeInst>(); for(Geometric geom : highs) { if (!(geom instanceof ArcInst)) continue; ArcInst ai = (ArcInst)geom; if (ai.getProto() != oldAi.getProto()) continue; changedAlready.add(ai); } if (connected) { Netlist netlist = cell.getNetlist(); for(Iterator<ArcInst> it = cell.getArcs(); it.hasNext(); ) { ArcInst ai = it.next(); if (ai.getProto() != oldAi.getProto()) continue; if (!netlist.sameNetwork(ai, oldAi)) continue; changedAlready.add(ai); } } if (thiscell) { for(Iterator<ArcInst> it = cell.getArcs(); it.hasNext(); ) { ArcInst ai = it.next(); if (ai.getProto() != oldAi.getProto()) continue; changedAlready.add(ai); } } for(Iterator<NodeInst> it = cell.getNodes(); it.hasNext(); ) { NodeInst ni = it.next(); if (ni.isCellInstance()) continue; if (!ni.getFunction().isPin()) continue; boolean allArcs = true; for(Iterator<Connection> cIt = ni.getConnections(); cIt.hasNext(); ) { Connection con = cIt.next(); if (!changedAlready.contains(con.getArc())) { allArcs = false; break; } } if (ni.hasConnections() && allArcs) changePins.add(ni); } } private void updateChangeCount() { Set<Geometric> changedAlready = new HashSet<Geometric>(); Cell cell = WindowFrame.getCurrentCell(); String toChange = ""; for (Geometric geomToChange : geomsToChange) { // count node replacement if (geomToChange instanceof NodeInst) { // get node to be replaced toChange = "nodes"; NodeInst ni = (NodeInst)geomToChange; NodeProto oldNType = ni.getProto(); changedAlready.add(ni); // count additional replacements if requested if (changeEverywhere.isSelected()) { // replace in all cells of library if requested for(Iterator<Library> it = Library.getLibraries(); it.hasNext(); ) { Library lib = it.next(); for(Iterator<Cell> cIt = lib.getCells(); cIt.hasNext(); ) { Cell c = cIt.next(); for(Iterator<NodeInst> nIt = c.getNodes(); nIt.hasNext(); ) { NodeInst lNi = nIt.next(); if (lNi.getProto() == oldNType) changedAlready.add(lNi); } } } } else if (changeInLibrary.isSelected()) { // replace throughout the library containing "this cell" if requested Library lib = cell.getLibrary(); for(Iterator<Cell> cIt = lib.getCells(); cIt.hasNext(); ) { Cell c = cIt.next(); for(Iterator<NodeInst> nIt = c.getNodes(); nIt.hasNext(); ) { NodeInst lNi = nIt.next(); if (lNi.getProto() == oldNType) changedAlready.add(lNi); } } } else if (changeInCell.isSelected()) { // replace throughout this cell if requested for(Iterator<NodeInst> nIt = cell.getNodes(); nIt.hasNext(); ) { NodeInst lNi = nIt.next(); if (lNi.getProto() == oldNType) changedAlready.add(lNi); } } else if (changeConnected.isSelected()) { // replace all connected to this in the cell if requested Netlist netlist = cell.getNetlist(); for(Iterator<NodeInst> it = cell.getNodes(); it.hasNext(); ) { NodeInst lNi = it.next(); if (lNi.getProto() != oldNType) continue; boolean found = false; for(Iterator<PortInst> pIt = ni.getPortInsts(); pIt.hasNext(); ) { PortInst pi = pIt.next(); for(Iterator<PortInst> lPIt = lNi.getPortInsts(); lPIt.hasNext(); ) { PortInst lPi = lPIt.next(); if (netlist.sameNetwork(pi.getNodeInst(), pi.getPortProto(), lPi.getNodeInst(), lPi.getPortProto())) { found = true; break; } } if (found) break; } if (found) changedAlready.add(lNi); } } } else { // count arc replacement toChange = "arcs"; ArcInst ai = (ArcInst)geomToChange; ArcProto oldAType = ai.getProto(); // special case when replacing nodes, too if (changeNodesWithArcs.isSelected()) { List<Geometric> highs = wnd.getHighlighter().getHighlightedEObjs(true, true); if (changeInLibrary.isSelected()) { for(Iterator<Cell> it = Library.getCurrent().getCells(); it.hasNext(); ) { Cell e = it.next(); countAllArcs(e, highs, ai, false, true, changedAlready); } } else { countAllArcs(ai.getParent(), highs, ai, changeConnected.isSelected(), changeInCell.isSelected(), changedAlready); } } else { // replace the arcinst changedAlready.add(ai); // do additional replacements if requested if (changeEverywhere.isSelected()) { // replace in all cells of library if requested for(Iterator<Library> it = Library.getLibraries(); it.hasNext(); ) { Library lib = it.next(); for(Iterator<Cell> cIt = lib.getCells(); cIt.hasNext(); ) { Cell c = cIt.next(); for(Iterator<ArcInst> nIt = c.getArcs(); nIt.hasNext(); ) { ArcInst lAi = nIt.next(); if (lAi.getProto() == oldAType) changedAlready.add(lAi); } } } } else if (changeInLibrary.isSelected()) { // replace throughout this library if requested Library lib = Library.getCurrent(); for(Iterator<Cell> cIt = lib.getCells(); cIt.hasNext(); ) { Cell c = cIt.next(); for(Iterator<ArcInst> nIt = c.getArcs(); nIt.hasNext(); ) { ArcInst lAi = nIt.next(); if (lAi.getProto() == oldAType) changedAlready.add(lAi); } } } else if (changeInCell.isSelected()) { // replace throughout this cell if requested for(Iterator<ArcInst> nIt = cell.getArcs(); nIt.hasNext(); ) { ArcInst lAi = nIt.next(); if (lAi.getProto() == oldAType) changedAlready.add(lAi); } } else if (changeConnected.isSelected()) { // replace all connected to this if requested Netlist netlist = cell.getNetlist(); for(Iterator<ArcInst> it = cell.getArcs(); it.hasNext(); ) { ArcInst lAi = it.next(); if (netlist.sameNetwork(ai, lAi)) changedAlready.add(lAi); } } } } } int num = changedAlready.size(); changeCount.setText("Selected " + num + " " + toChange); } private static final Pattern dummyName = Pattern.compile("(.*?)FROM(.*?)\\{(.*)"); /** * Method called when the current selection has changed. * Makes sure displayed options are correct. */ private void loadInfo(boolean showHighlighted) { // update current window EditWindow curWnd = EditWindow.getCurrent(); if (curWnd != null) wnd = curWnd; // find out what is going to be changed geomsToChange = new ArrayList<Geometric>(); if (wnd != null) { List<Geometric> highs = wnd.getHighlighter().getHighlightedEObjs(true, true); boolean hasArcs = false, hasCells = false, hasPrimitives = false; for (Geometric geom : highs) { geomsToChange.add(geom); if (geom instanceof ArcInst) hasArcs = true; else if (geom instanceof NodeInst) { NodeInst ni = (NodeInst)geom; if (ni.isCellInstance()) hasCells = true; else hasPrimitives = true; } } if (hasArcs && hasCells) { System.out.println("The 'Change' dialog cannot handle selection of both arcs and cells." + "\n Close the dialog if the selection of elements is correct."); geomsToChange.clear(); } else if (hasArcs && hasPrimitives) { System.out.println("The 'Change' dialog cannot handle selection of both arcs and primitives." + "\n Close the dialog if the selection of elements is correct."); geomsToChange.clear(); } else if (hasCells && hasPrimitives) { System.out.println("The 'Change' dialog cannot handle selection of both cells and primitives." + "\n Close the dialog if the selection of elements is correct."); geomsToChange.clear(); } } if (geomsToChange.size() == 0) { librariesPopup.setEnabled(false); ignorePortNames.setEnabled(false); allowMissingPorts.setEnabled(false); showPrimitives.setEnabled(false); showCells.setEnabled(false); changeNodesWithArcs.setEnabled(false); apply.setEnabled(false); changeSelected.setEnabled(false); changeConnected.setEnabled(false); changeInCell.setEnabled(false); changeInLibrary.setEnabled(false); changeEverywhere.setEnabled(false); return; } apply.setEnabled(true); changeSelected.setEnabled(true); changeConnected.setEnabled(true); changeInCell.setEnabled(true); changeInLibrary.setEnabled(true); changeEverywhere.setEnabled(true); Geometric geomToChange = geomsToChange.get(0); if (geomToChange instanceof NodeInst) { librariesPopup.setEnabled(true); ignorePortNames.setEnabled(true); allowMissingPorts.setEnabled(true); showPrimitives.setEnabled(true); showCells.setEnabled(true); NodeInst ni = (NodeInst)geomToChange; if (ni.isCellInstance()) { showCells.setSelected(true); } else { showPrimitives.setSelected(true); } changeNodesWithArcs.setSelected(false); changeNodesWithArcs.setEnabled(false); } else { librariesPopup.setEnabled(false); ignorePortNames.setEnabled(false); allowMissingPorts.setEnabled(false); showPrimitives.setEnabled(false); showCells.setEnabled(false); changeNodesWithArcs.setEnabled(true); changeNodesWithArcs.setSelected(lastChangeNodesWithArcs); } reload(true); } private void rememberState() { lastIgnorePortNames = ignorePortNames.isSelected(); lastAllowMissingPorts = allowMissingPorts.isSelected(); } private boolean dontReload = false; /** * Method called when dialog controls have changed. * Makes sure the displayed lists and options are correct. */ private void reload(boolean canSwitchLibraries) { lastChangeNodesWithArcs = changeNodesWithArcs.isSelected(); if (dontReload) return; ExplorerTree.KeepTreeExpansion kte = new ExplorerTree.KeepTreeExpansion(changeTree, rootNode, treeModel, new TreePath(rootNode)); rootCells.removeAllChildren(); rootPrims.removeAllChildren(); rootArcs.removeAllChildren(); changeNodeProtoList.clear(); changeArcProtoList.clear(); changeNodeProtoFunctionList.clear(); if (geomsToChange.size() == 0) return; Technology curTech = Technology.getCurrent(); Geometric geomToChange = geomsToChange.get(0); if (geomToChange instanceof NodeInst) { NodeInst ni = (NodeInst)geomToChange; if (showCells.isSelected()) { // cell: only list other cells as replacements if (ni.isCellInstance() && canSwitchLibraries) { Cell parent = (Cell)ni.getProto(); Library lib = parent.getLibrary(); dontReload = true; librariesPopup.setSelectedItem(lib.getName()); dontReload = false; } View origView = null; if (ni.isCellInstance()) origView = ((Cell)ni.getProto()).getView(); String libName = (String)librariesPopup.getSelectedItem(); Library lib = Library.findLibrary(libName); for(Iterator<Cell> it = lib.getCells(); it.hasNext(); ) { Cell cell = it.next(); if (origView != null) { // filter according to original node's view if (origView == View.ICON) { if (cell.getView() != View.ICON) continue; } else if (origView == View.LAYOUT || origView == View.LAYOUTCOMP || origView == View.LAYOUTSKEL) { if (cell.getView() != View.LAYOUT && cell.getView() != View.LAYOUTCOMP && cell.getView() != View.LAYOUTSKEL) continue; } } DefaultMutableTreeNode dmtn = new DefaultMutableTreeNode(cell.noLibDescribe()); rootCells.add(dmtn); changeNodeProtoList.put(dmtn, cell); } } if (showPrimitives.isSelected()) { // primitive: list primitives in this and the generic technology for(PrimitiveNode np : curTech.getNodesSortedByName()) { if (np.isNotUsed()) continue; // skip primitives not in use Map<Function,String> specialList = specialSchematics.get(np); if (specialList != null) { Map<String,Function> subNames = new TreeMap<String,Function>(); for(Function fun : specialList.keySet()) subNames.put(specialList.get(fun), fun); DefaultMutableTreeNode subPrims = new DefaultMutableTreeNode(np.describe(false)); rootPrims.add(subPrims); for(String subName : subNames.keySet()) { Function fun = subNames.get(subName); DefaultMutableTreeNode dmtn = new DefaultMutableTreeNode(subName); subPrims.add(dmtn); changeNodeProtoList.put(dmtn, np); changeNodeProtoFunctionList.put(dmtn, fun); } } else { DefaultMutableTreeNode dmtn = new DefaultMutableTreeNode(np.describe(false)); rootPrims.add(dmtn); changeNodeProtoList.put(dmtn, np); } } if (curTech != Generic.tech()) { DefaultMutableTreeNode dmtn = new DefaultMutableTreeNode("Generic:Universal-Pin"); rootPrims.add(dmtn); changeNodeProtoList.put(dmtn, Generic.tech().universalPinNode); dmtn = new DefaultMutableTreeNode("Generic:Invisible-Pin"); rootPrims.add(dmtn); changeNodeProtoList.put(dmtn, Generic.tech().invisiblePinNode); dmtn = new DefaultMutableTreeNode("Generic:Unrouted-Pin"); rootPrims.add(dmtn); changeNodeProtoList.put(dmtn, Generic.tech().unroutedPinNode); } } // try to select prototype of selected node for(DefaultMutableTreeNode dmtn : changeNodeProtoList.keySet()) { NodeProto np = changeNodeProtoList.get(dmtn); Function fun = changeNodeProtoFunctionList.get(dmtn); if (np == ni.getProto()) { TreePath path = new TreePath(rootNode); if (ni.isCellInstance()) { path = path.pathByAddingChild(rootCells); } else { path = path.pathByAddingChild(rootPrims); } if (fun != null) { if (ni.getFunction() != fun) continue; DefaultMutableTreeNode parent = (DefaultMutableTreeNode)dmtn.getParent(); path = path.pathByAddingChild(parent); } path = path.pathByAddingChild(dmtn); changeTree.expandPath(path); changeTree.setSelectionPath(path); SwingUtilities.invokeLater(new MyRunnable(path)); break; } } if (showCells.isSelected()) { String geomName = ((NodeInst)geomToChange).getProto().describe(false); // if replacing dummy facet, name will be [cellname]FROM[libname][{view}] Matcher mat = dummyName.matcher(geomName); if (mat.matches()) { // try to select items. Nothing will happen if they are not in list. // changeList.setSelectedValue(mat.group(1) + "{" + mat.group(3), true); librariesPopup.setSelectedItem(mat.group(2)); } else { // otherwise, try to match name // changeList.setSelectedValue(geomName, true); } } } else { // load arcs in current technology, arc's technology, and generic technology ArcInst ai = (ArcInst)geomToChange; PortProto pp1 = ai.getHeadPortInst().getPortProto(); PortProto pp2 = ai.getTailPortInst().getPortProto(); for(Iterator<ArcProto> it = curTech.getArcs(); it.hasNext(); ) { ArcProto ap = it.next(); if (ap.isNotUsed()) continue; if (!changeNodesWithArcs.isSelected()) { if (!pp1.connectsTo(ap)) continue; if (!pp2.connectsTo(ap)) continue; } DefaultMutableTreeNode dmtn = new DefaultMutableTreeNode(ap.describe()); rootArcs.add(dmtn); changeArcProtoList.put(dmtn, ap); } if (curTech != Generic.tech()) { for(Iterator<ArcProto> it = Generic.tech().getArcs(); it.hasNext(); ) { ArcProto ap = it.next(); if (ap.isNotUsed()) continue; if (!changeNodesWithArcs.isSelected()) { if (!pp1.connectsTo(ap)) continue; if (!pp2.connectsTo(ap)) continue; } DefaultMutableTreeNode dmtn = new DefaultMutableTreeNode(ap.describe()); rootArcs.add(dmtn); changeArcProtoList.put(dmtn, ap); } } Technology arcTech = ai.getProto().getTechnology(); if (arcTech != curTech && arcTech != Generic.tech()) { for(Iterator<ArcProto> it = arcTech.getArcs(); it.hasNext(); ) { ArcProto ap = it.next(); if (ap.isNotUsed()) continue; if (!changeNodesWithArcs.isSelected()) { if (!pp1.connectsTo(ap)) continue; if (!pp2.connectsTo(ap)) continue; } DefaultMutableTreeNode dmtn = new DefaultMutableTreeNode(ap.describe()); rootArcs.add(dmtn); changeArcProtoList.put(dmtn, ap); } } for(DefaultMutableTreeNode dmtn : changeArcProtoList.keySet()) { ArcProto ap = changeArcProtoList.get(dmtn); if (ap == ai.getProto()) { TreePath path = new TreePath(rootNode); path = path.pathByAddingChild(rootArcs); path = path.pathByAddingChild(dmtn); changeTree.expandPath(path); changeTree.setSelectionPath(path); SwingUtilities.invokeLater(new MyRunnable(path)); break; } } } changeTree.updateUI(); kte.restore(); updateChangeCount(); } private class MyRunnable implements Runnable { private TreePath path; MyRunnable(TreePath path) { this.path = path; } public void run() { changeTree.scrollPathToVisible(path); } } private void doTheChange() { NodeProto np = null; ArcProto ap = null; Function func = null; Geometric geomToChange = geomsToChange.get(0); if (geomToChange instanceof NodeInst) { np = changeNodeProtoList.get(currentlySelected); func = changeNodeProtoFunctionList.get(currentlySelected); } else { ap = changeArcProtoList.get(currentlySelected); if (ap == null) { System.out.println("Nothing is selected"); return; } } List<Geometric> highs = wnd.getHighlighter().getHighlightedEObjs(true, true); new ChangeObject(geomsToChange, highs, getLibSelected(), np, func, ap, ignorePortNames.isSelected(), allowMissingPorts.isSelected(), changeNodesWithArcs.isSelected(), changeInCell.isSelected(), changeInLibrary.isSelected(), changeEverywhere.isSelected(), changeConnected.isSelected()); } /** * Class to change the node/arc type in a new thread. */ private static class ChangeObject extends Job { private static final long serialVersionUID = 1L; private List<Geometric> geomsToChange, highs; private String libName; private NodeProto np; private ArcProto ap; private Cell cell; private boolean ignorePortNames, allowMissingPorts, changeNodesWithArcs; private boolean changeInCell, changeInLibrary, changeEverywhere, changeConnected; private Function func; private List<Geometric> highlightThese; private ChangeObject(List<Geometric> geomsToChange, List<Geometric> highs, String libName, NodeProto np, Function func, ArcProto ap, boolean ignorePortNames, boolean allowMissingPorts, boolean changeNodesWithArcs, boolean changeInCell, boolean changeInLibrary, boolean changeEverywhere, boolean changeConnected) { super("Change type", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER); this.geomsToChange = geomsToChange; this.highs = highs; this.libName = libName; this.np = np; this.func = func; this.ap = ap; this.cell = WindowFrame.getCurrentCell(); this.ignorePortNames = ignorePortNames; this.allowMissingPorts = allowMissingPorts; this.changeNodesWithArcs = changeNodesWithArcs; this.changeInCell = changeInCell; this.changeInLibrary = changeInLibrary; this.changeEverywhere = changeEverywhere; this.changeConnected = changeConnected; startJob(); } public boolean doIt() throws JobException { highlightThese = new ArrayList<Geometric>(); fieldVariableChanged("highlightThese"); Set<Geometric> changedAlready = new HashSet<Geometric>(); MutableInteger nodeFailures = new MutableInteger(0); for (Geometric geomToChange : geomsToChange) { // handle node replacement if (geomToChange instanceof NodeInst) { // get node to be replaced NodeInst ni = (NodeInst)geomToChange; NodeProto oldNType = ni.getProto(); // disallow replacing if lock is on if (CircuitChangeJobs.cantEdit(ni.getParent(), ni, true, false, true) != 0) return false; // get nodeproto to replace it with Library library = Library.findLibrary(libName); if (library == null) return false; if (np == null) return false; // replace the selected node int total = 0; NodeInst onlyNewNi = updateNodeInst(ni, changedAlready, nodeFailures); if (onlyNewNi != null) { highlightThese.add(onlyNewNi); total++; } String replacedWith = "node " + np.describe(false); if (func != null) replacedWith += " (" + func.getShortName() + ")"; // do additional replacements if requested if (changeEverywhere) { // replace in all cells of library if requested for(Iterator<Library> it = Library.getLibraries(); it.hasNext(); ) { Library lib = it.next(); for(Iterator<Cell> cIt = lib.getCells(); cIt.hasNext(); ) { Cell cell = cIt.next(); boolean found = true; while (found) { found = false; for(Iterator<NodeInst> nIt = cell.getNodes(); nIt.hasNext(); ) { NodeInst lNi = nIt.next(); if (lNi.getProto() != oldNType) continue; // do not replace the example icon if (lNi.isIconOfParent()) { System.out.println("Example icon in " + cell + " not replaced"); continue; } // disallow replacing if lock is on int errorCode = CircuitChangeJobs.cantEdit(cell, lNi, true, false, true); if (errorCode < 0) return false; if (errorCode > 0) continue; NodeInst newNi = updateNodeInst(lNi, changedAlready, nodeFailures); if (newNi != null) { total++; found = true; break; } } } } } if (total > 0) System.out.println("All " + total + " " + oldNType.describe(true) + " nodes in all libraries replaced with " + replacedWith); } else if (changeInLibrary) { // replace throughout the library containing "this cell" if requested Library lib = cell.getLibrary(); for(Iterator<Cell> cIt = lib.getCells(); cIt.hasNext(); ) { Cell cell = cIt.next(); boolean found = true; while (found) { found = false; for(Iterator<NodeInst> nIt = cell.getNodes(); nIt.hasNext(); ) { NodeInst lNi = nIt.next(); if (lNi.getProto() != oldNType) continue; // disallow replacing if lock is on int errorCode = CircuitChangeJobs.cantEdit(cell, lNi, true, false, true); if (errorCode < 0) return false; if (errorCode > 0) continue; NodeInst newNi = updateNodeInst(lNi, changedAlready, nodeFailures); if (newNi != null) { total++; found = true; break; } } } } if (total > 0) System.out.println("All " + total + " " + oldNType.describe(true) + " nodes in " + lib + " replaced with " + replacedWith); } else if (changeInCell) { // replace throughout this cell if requested boolean found = true; while (found) { found = false; for(Iterator<NodeInst> nIt = cell.getNodes(); nIt.hasNext(); ) { NodeInst lNi = nIt.next(); if (lNi.getProto() != oldNType) continue; // disallow replacing if lock is on int errorCode = CircuitChangeJobs.cantEdit(cell, lNi, true, false, true); if (errorCode < 0) return false; if (errorCode > 0) continue; NodeInst newNi = updateNodeInst(lNi, changedAlready, nodeFailures); if (newNi != null) { total++; found = true; break; } } } if (total > 0) System.out.println("All " + total + " " + oldNType.describe(true) + " nodes in " + cell + " replaced with " + replacedWith); } else if (changeConnected) { // replace all connected to this in the cell if requested Netlist netlist = cell.getNetlist(); List<NodeInst> others = new ArrayList<NodeInst>(); NodeInst newNi = null; if (highlightThese.size() == 1 && highlightThese.get(0) instanceof NodeInst) newNi = (NodeInst)highlightThese.get(0); for(Iterator<NodeInst> it = cell.getNodes(); it.hasNext(); ) { NodeInst lNi = it.next(); if (lNi.getProto() != oldNType) continue; if (lNi == newNi) continue; boolean found = false; for(Iterator<PortInst> pIt = newNi.getPortInsts(); pIt.hasNext(); ) { PortInst pi = pIt.next(); for(Iterator<PortInst> lPIt = lNi.getPortInsts(); lPIt.hasNext(); ) { PortInst lPi = lPIt.next(); if (netlist.sameNetwork(pi.getNodeInst(), pi.getPortProto(), lPi.getNodeInst(), lPi.getPortProto())) { found = true; break; } } if (found) break; } if (found) others.add(lNi); } // make the changes for(NodeInst lNi : others) { // disallow replacing if lock is on int errorCode = CircuitChangeJobs.cantEdit(cell, lNi, true, false, true); if (errorCode < 0) return false; if (errorCode > 0) continue; NodeInst newNode = updateNodeInst(lNi, changedAlready, nodeFailures); if (newNode != null) total++; } if (total > 0) System.out.println("All " + total + " " + oldNType.describe(true) + " nodes connected to this replaced with " + replacedWith); } else { if (total > 0) System.out.println(oldNType + " replaced with " + replacedWith); } } else { // get arc to be replaced ArcInst ai = (ArcInst)geomToChange; if (ap == null) { System.out.println("Arc " + ai.getName() + " skipped"); continue; } // disallow replacement if lock is on if (CircuitChangeJobs.cantEdit(ai.getParent(), null, true, false, true) != 0) return false; // sanity check ArcProto oldAType = ai.getProto(); if (oldAType == ap) { System.out.println("Arc already of type " + ap.describe()); return false; } // special case when replacing nodes, too if (changeNodesWithArcs) { if (changeInLibrary) { for(Iterator<Cell> it = Library.getCurrent().getCells(); it.hasNext(); ) { Cell cell = it.next(); replaceAllArcs(cell, highs, ai, ap, false, true); } } else { replaceAllArcs(ai.getParent(), highs, ai, ap, changeConnected, changeInCell); } return true; } // replace the arcinst ArcInst onlyNewAi = ai.replace(ap); if (onlyNewAi == null) { System.out.println(ap + " does not fit in the place of " + oldAType); return false; } highlightThese.add(onlyNewAi); // do additional replacements if requested int total = 1; if (changeEverywhere) { // replace in all cells of library if requested for(Iterator<Library> it = Library.getLibraries(); it.hasNext(); ) { Library lib = it.next(); for(Iterator<Cell> cIt = lib.getCells(); cIt.hasNext(); ) { Cell cell = cIt.next(); boolean found = true; while (found) { found = false; for(Iterator<ArcInst> nIt = cell.getArcs(); nIt.hasNext(); ) { ArcInst lAi = nIt.next(); if (lAi.getProto() != oldAType) continue; // disallow replacing if lock is on int errorCode = CircuitChangeJobs.cantEdit(cell, null, true, false, true); if (errorCode < 0) return false; if (errorCode > 0) continue; ArcInst newAi = lAi.replace(ap); if (newAi != null) { total++; found = true; break; } } } } } System.out.println("All " + total + " " + oldAType.describe() + " arcs in the library replaced with " + ap); } else if (changeInLibrary) { // replace throughout this library if requested Library lib = Library.getCurrent(); for(Iterator<Cell> cIt = lib.getCells(); cIt.hasNext(); ) { Cell cell = cIt.next(); boolean found = true; while (found) { found = false; for(Iterator<ArcInst> nIt = cell.getArcs(); nIt.hasNext(); ) { ArcInst lAi = nIt.next(); if (lAi.getProto() != oldAType) continue; // disallow replacing if lock is on int errorCode = CircuitChangeJobs.cantEdit(cell, null, true, false, true); if (errorCode < 0) return false; if (errorCode > 0) continue; ArcInst newAi = lAi.replace(ap); if (newAi != null) { total++; found = true; break; } } } } System.out.println("All " + total + " " + oldAType.describe() + " arcs in " + lib + " replaced with " + ap); } else if (changeInCell) { // replace throughout this cell if requested boolean found = true; while (found) { found = false; for(Iterator<ArcInst> nIt = cell.getArcs(); nIt.hasNext(); ) { ArcInst lAi = nIt.next(); if (lAi.getProto() != oldAType) continue; // disallow replacing if lock is on int errorCode = CircuitChangeJobs.cantEdit(cell, null, true, false, true); if (errorCode < 0) return false; if (errorCode > 0) continue; ArcInst newAi = lAi.replace(ap); if (newAi != null) { total++; found = true; break; } } } System.out.println("All " + total + " " + oldAType.describe() + " arcs in " + cell + " replaced with " + ap); } else if (changeConnected) { // replace all connected to this if requested List<ArcInst> others = new ArrayList<ArcInst>(); Netlist netlist = cell.getNetlist(); for(Iterator<ArcInst> it = cell.getArcs(); it.hasNext(); ) { ArcInst lAi = it.next(); if (lAi == onlyNewAi) continue; if (netlist.sameNetwork(onlyNewAi, lAi)) others.add(lAi); } for(ArcInst lAi : others) { ArcInst newAi = lAi.replace(ap); if (newAi != null) total++; } System.out.println("All " + total + " " + oldAType.describe() + " arcs connected to this replaced with " + ap); } else System.out.println(oldAType + " replaced with " +ap); } } if (nodeFailures.intValue() > 0) { JOptionPane.showMessageDialog(Main.getCurrentJFrame(), "There were " + nodeFailures.intValue() + " nodes that could not be replaced with " + np, "Change failed", JOptionPane.ERROR_MESSAGE); } return true; } /** * Method to update a node with the replacement type. * @param ni the node to update * @param changedAlready a Set of nodes already updates. * @return a node to highlight (because it was changed). May be null. */ private NodeInst updateNodeInst(NodeInst ni, Set<Geometric> changedAlready, MutableInteger failures) { if (changedAlready.contains(ni)) return null; NodeProto oldNType = ni.getProto(); boolean noChange = oldNType == np; if (noChange) { if (func != null) { Function oldFunc = ni.getFunction(); if (func != oldFunc) noChange = false; } } if (noChange) { System.out.println("Node already of type " + np.describe(true)); // just skip this case. No need to redo it. This not an error. return null; } // replace the nodeinsts changedAlready.add(ni); NodeInst onlyNewNi = ni; if (oldNType != np) { onlyNewNi = CircuitChangeJobs.replaceNodeInst(ni, np, ignorePortNames, allowMissingPorts); if (onlyNewNi == null) { System.out.println(np + " does not fit in the place of " + oldNType); failures.increment(); return null; } } if (func != null) onlyNewNi.setTechSpecific(Schematics.getPrimitiveFunctionBits(func)); return onlyNewNi; } public void terminateOK() { EditWindow wnd = EditWindow.getCurrent(); if (wnd != null) { Highlighter highlighter = wnd.getHighlighter(); for(Geometric geom : highlightThese) { highlighter.addElectricObject(geom, geom.getParent()); } highlighter.finished(); } } /** * Method to replace arc "oldAi" with another of type "ap", adding layer-change contacts * as needed to keep the connections. If "connected" is true, replace all such arcs * connected to this. If "thiscell" is true, replace all such arcs in the cell. */ private void replaceAllArcs(Cell cell, List<Geometric> highs, ArcInst oldAi, ArcProto ap, boolean connected, boolean thiscell) { Set<Geometric> geomMarked = new HashSet<Geometric>(); List<NodeInst> changePins = new ArrayList<NodeInst>(); for(Geometric geom : highs) { if (!(geom instanceof ArcInst)) continue; ArcInst ai = (ArcInst)geom; if (ai.getProto() != oldAi.getProto()) continue; geomMarked.add(ai); } if (connected) { Netlist netlist = cell.getNetlist(); for(Iterator<ArcInst> it = cell.getArcs(); it.hasNext(); ) { ArcInst ai = it.next(); if (ai.getProto() != oldAi.getProto()) continue; if (!netlist.sameNetwork(ai, oldAi)) continue; geomMarked.add(ai); } } if (thiscell) { for(Iterator<ArcInst> it = cell.getArcs(); it.hasNext(); ) { ArcInst ai = it.next(); if (ai.getProto() != oldAi.getProto()) continue; geomMarked.add(ai); } } for(Iterator<NodeInst> it = cell.getNodes(); it.hasNext(); ) { NodeInst ni = it.next(); if (ni.isCellInstance()) continue; if (!ni.getFunction().isPin()) continue; boolean allArcs = true; for(Iterator<Connection> cIt = ni.getConnections(); cIt.hasNext(); ) { Connection con = cIt.next(); if (!geomMarked.contains(con.getArc())) { allArcs = false; break; } } if (ni.hasConnections() && allArcs) changePins.add(ni); } // now create new pins where they belong EditingPreferences ep = cell.getEditingPreferences(); PrimitiveNode pin = ap.findOverridablePinProto(ep); double xS = pin.getDefWidth(); double yS = pin.getDefHeight(); Map<NodeInst,NodeInst> newNodes = new HashMap<NodeInst,NodeInst>(); for(NodeInst ni : changePins) { NodeInst newNi = NodeInst.makeInstance(pin, ni.getAnchorCenter(), xS, yS, cell); if (newNi == null) return; newNodes.put(ni, newNi); // move exports for(Iterator<Export> eIt = ni.getExports(); eIt.hasNext(); ) { Export oldExport = eIt.next(); if (oldExport.move(newNi.getOnlyPortInst())) { System.out.println("Unable to move export " + oldExport.getName() + " from old pin " + ni.describe(true) + " to new pin " + newNi); } } } // now create new arcs to replace the old ones for(Geometric geom : geomMarked) { if (!(geom instanceof ArcInst)) continue; ArcInst ai = (ArcInst)geom; PortInst pi0 = null; NodeInst newNi0 = newNodes.get(ai.getHeadPortInst().getNodeInst()); if (newNi0 != null) { pi0 = newNi0.getOnlyPortInst(); } else { // need contacts to get to the right level pi0 = makeContactStack(ai, ArcInst.HEADEND, ap); if (pi0 == null) return; } PortInst pi1 = null; NodeInst newNi1 = newNodes.get(ai.getTailPortInst().getNodeInst()); if (newNi1 != null) { pi1 = newNi1.getOnlyPortInst(); } else { // need contacts to get to the right level pi1 = makeContactStack(ai, ArcInst.TAILEND, ap); if (pi1 == null) return; } double wid = ap.getDefaultLambdaBaseWidth(); if (ai.getLambdaBaseWidth() > wid) wid = ai.getLambdaBaseWidth(); ArcInst newAi = ArcInst.makeInstanceBase(ap, wid, pi0, pi1, ai.getHeadLocation(), ai.getTailLocation(), ai.getName()); if (newAi == null) return; newAi.copyPropertiesFrom(ai); geomMarked.remove(newAi); } // now remove the previous arcs and nodes for(Geometric geom : geomMarked) { if (geom instanceof ArcInst) { ArcInst ai = (ArcInst)geom; ai.kill(); } } // delete old pins and copy their names to the new ones for(NodeInst ni : changePins) { if (!ni.hasExports()) { String niName = ni.getName(); ni.kill(); NodeInst newNi = newNodes.get(ni); newNi.setName(niName); } } } private NodeProto [] contactStack = new NodeProto[100]; private ArcProto [] contactStackArc = new ArcProto[100]; private Technology connectionTech = null; private Map<ArcProto,Map<ArcProto,PrimitivePort>> connectionMap; /** * Method to examine end "end" of arc "ai" and return a node at that position which * can connect to arcs of type "ap". This may require creation of one or more contacts * to change layers. */ private PortInst makeContactStack(ArcInst ai, int end, ArcProto ap) { NodeInst lastNi = ai.getPortInst(end).getNodeInst(); PortProto lastPp = ai.getPortInst(end).getPortProto(); PortInst lastPi = lastNi.findPortInstFromProto(lastPp); Point2D center = ai.getLocation(end); Cell cell = ai.getParent(); // setup map of contacts in the technology setupConnections(ap.getTechnology()); // find the path of contacts to make the connection Set<ArcProto> markedArcs = new HashSet<ArcProto>(); int depth = findOtherPathToArc(lastPp, ai.getProto(), ap, 0, markedArcs); if (depth < 0) return null; // create the contacts for(int i=0; i<depth; i++) { ArcProto typ = contactStackArc[i]; double wid = ai.getLambdaBaseWidth(); double xS = contactStack[i].getDefWidth(); double yS = contactStack[i].getDefHeight(); SizeOffset so = contactStack[i].getProtoSizeOffset(); xS = Math.max(xS - so.getLowXOffset() - so.getHighXOffset(), wid) + so.getLowXOffset() + so.getHighXOffset(); yS = Math.max(yS - so.getLowYOffset() - so.getHighYOffset(), wid) + so.getLowYOffset() + so.getHighYOffset(); NodeInst newNi = NodeInst.makeInstance(contactStack[i], center, xS, yS, cell); if (newNi == null) return null; PortInst thisPi = newNi.findPortInstFromProto(contactStack[i].getPort(0)); ArcInst newAi = ArcInst.newInstanceBase(typ, wid, thisPi, lastPi, center, center, null, ai.getAngle()); lastPi = thisPi; if (newAi == null) return null; newAi.setFixedAngle(true); } return lastPi; } /** * Method to setup the contact network for a given Technology. * This network shows which contacts can be used to move from one ArcProto to another. * @param tech the Technology to setup. */ private void setupConnections(Technology tech) { if (connectionTech == tech) return; connectionTech = tech; connectionMap = new HashMap<ArcProto,Map<ArcProto,PrimitivePort>>(); for(Iterator<PrimitiveNode> it = tech.getNodes(); it.hasNext(); ) { PrimitiveNode np = it.next(); if (np.isNotUsed()) continue; PrimitiveNode.Function fun = np.getFunction(); if (!fun.isContact()) continue; PrimitivePort pp = np.getPort(0); ArcProto[] arcs = pp.getConnections(); ArcProto ap1 = null, ap2 = null; for(int i=0; i<arcs.length; i++) { ArcProto ap = arcs[i]; if (ap.getTechnology() != tech) continue; if (ap1 == null) ap1 = ap; else if (ap2 == null) ap2 = ap; } if (ap1 == null || ap2 == null) continue; addConnection(ap1, ap2, null); addConnection(ap2, ap1, null); } } /** * Method to update the contact network. * @param ap1 an ArcProto. * @param ap2 another ArcProto. * @param np the contact that connects them. */ private void addConnection(ArcProto ap1, ArcProto ap2, PrimitivePort np) { Map<ArcProto,PrimitivePort> arcMap = connectionMap.get(ap1); if (arcMap == null) connectionMap.put(ap1, arcMap = new HashMap<ArcProto,PrimitivePort>()); if (arcMap.get(ap2) == null) { PrimitivePort pp = User.getUserTool().getCurrentContactPortProto(ap1, ap2); if (pp == null) System.out.println("NULL PORT CONNECTING "+ap1.describe()+" AND "+ap2.describe()); arcMap.put(ap2, pp); } } /** * Method to compute an array of contacts and arcs that connects a port to an arcproto. * @param pp the original port. * @param sourceAp the source ArcProto. * @param destAp the destination ArcProto. * @param depth the location in the contact array to fill. * @param markedArcs a set of Arcprotos that have been used in the search. * @return the new size of the contact array. */ private int findOtherPathToArc(PortProto pp, ArcProto sourceAp, ArcProto destAp, int depth, Set<ArcProto> markedArcs) { // see if the connection is made if (pp.connectsTo(destAp)) return depth; // look for a contact PrimitiveNode bestNp = null; ArcProto bestAp = null; int bestDepth = 0; Map<ArcProto,PrimitivePort> arcMap = connectionMap.get(sourceAp); for(ArcProto nextAp : arcMap.keySet()) { if (markedArcs.contains(nextAp)) continue; PortProto nextPp = arcMap.get(nextAp); if (nextPp == null) continue; PrimitiveNode nextNp = (PrimitiveNode)nextPp.getParent(); // this contact is part of the chain contactStack[depth] = nextNp; markedArcs.add(nextAp); int newDepth = findOtherPathToArc(nextPp, nextAp, destAp, depth+1, markedArcs); markedArcs.remove(nextAp); if (newDepth < 0) continue; if (bestNp == null || newDepth < bestDepth) { bestDepth = newDepth; bestNp = nextNp; bestAp = nextAp; } } if (bestNp != null) { contactStack[depth] = bestNp; contactStackArc[depth] = sourceAp; markedArcs.add(bestAp); int newDepth = findOtherPathToArc(bestNp.getPort(0), bestAp, destAp, depth+1, markedArcs); markedArcs.remove(bestAp); return newDepth; } return -1; } } private String getLibSelected() { return (String)librariesPopup.getSelectedItem(); } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; changeOption = new javax.swing.ButtonGroup(); done = new javax.swing.JButton(); apply = new javax.swing.JButton(); listPane = new javax.swing.JScrollPane(); changeSelected = new javax.swing.JRadioButton(); changeConnected = new javax.swing.JRadioButton(); changeInCell = new javax.swing.JRadioButton(); changeInLibrary = new javax.swing.JRadioButton(); changeEverywhere = new javax.swing.JRadioButton(); changeNodesWithArcs = new javax.swing.JCheckBox(); showPrimitives = new javax.swing.JCheckBox(); showCells = new javax.swing.JCheckBox(); ignorePortNames = new javax.swing.JCheckBox(); jLabel1 = new javax.swing.JLabel(); librariesPopup = new javax.swing.JComboBox(); allowMissingPorts = new javax.swing.JCheckBox(); changeCount = new javax.swing.JLabel(); setTitle("Change"); setName(""); // NOI18N addWindowListener(new java.awt.event.WindowAdapter() { public void windowClosing(java.awt.event.WindowEvent evt) { closeDialog(evt); } }); getContentPane().setLayout(new java.awt.GridBagLayout()); done.setText("Done"); done.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { done(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 11; gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); getContentPane().add(done, gridBagConstraints); apply.setText("Change"); apply.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { apply(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 3; gridBagConstraints.gridy = 11; gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); getContentPane().add(apply, gridBagConstraints); listPane.setMinimumSize(new java.awt.Dimension(150, 22)); listPane.setPreferredSize(new java.awt.Dimension(250, 22)); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = 2; gridBagConstraints.gridheight = 11; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); getContentPane().add(listPane, gridBagConstraints); changeOption.add(changeSelected); changeSelected.setText("Change selected ones only"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(4, 4, 2, 4); getContentPane().add(changeSelected, gridBagConstraints); changeOption.add(changeConnected); changeConnected.setText("Change all connected to this"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 1; gridBagConstraints.gridwidth = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(2, 4, 2, 4); getContentPane().add(changeConnected, gridBagConstraints); changeOption.add(changeInCell); changeInCell.setText("Change all in this cell"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 2; gridBagConstraints.gridwidth = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(2, 4, 2, 4); getContentPane().add(changeInCell, gridBagConstraints); changeOption.add(changeInLibrary); changeInLibrary.setText("Change all in this library"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 3; gridBagConstraints.gridwidth = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(2, 4, 2, 4); getContentPane().add(changeInLibrary, gridBagConstraints); changeOption.add(changeEverywhere); changeEverywhere.setText("Change all in all libraries"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 4; gridBagConstraints.gridwidth = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(2, 4, 10, 4); getContentPane().add(changeEverywhere, gridBagConstraints); changeNodesWithArcs.setText("Change nodes with arcs"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 6; gridBagConstraints.gridwidth = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(10, 4, 4, 4); getContentPane().add(changeNodesWithArcs, gridBagConstraints); showPrimitives.setText("Show primitives"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 7; gridBagConstraints.gridwidth = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); getContentPane().add(showPrimitives, gridBagConstraints); showCells.setText("Show cells"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 8; gridBagConstraints.gridwidth = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); getContentPane().add(showCells, gridBagConstraints); ignorePortNames.setText("Ignore port names"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 9; gridBagConstraints.gridwidth = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); getContentPane().add(ignorePortNames, gridBagConstraints); jLabel1.setText("Library:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 11; getContentPane().add(jLabel1, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 11; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); getContentPane().add(librariesPopup, gridBagConstraints); allowMissingPorts.setText("Allow missing ports"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 10; gridBagConstraints.gridwidth = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); getContentPane().add(allowMissingPorts, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 5; gridBagConstraints.gridwidth = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4); getContentPane().add(changeCount, gridBagConstraints); pack(); }// </editor-fold>//GEN-END:initComponents private void done(java.awt.event.ActionEvent evt)//GEN-FIRST:event_done {//GEN-HEADEREND:event_done closeDialog(null); }//GEN-LAST:event_done private void apply(java.awt.event.ActionEvent evt)//GEN-FIRST:event_apply {//GEN-HEADEREND:event_apply doTheChange(); libSelected = (String)librariesPopup.getSelectedItem(); }//GEN-LAST:event_apply /** Closes the dialog */ private void closeDialog(java.awt.event.WindowEvent evt)//GEN-FIRST:event_closeDialog { Highlighter.removeHighlightListener(this); setVisible(false); dispose(); theDialog = null; }//GEN-LAST:event_closeDialog // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JCheckBox allowMissingPorts; private javax.swing.JButton apply; private javax.swing.JRadioButton changeConnected; private javax.swing.JLabel changeCount; private javax.swing.JRadioButton changeEverywhere; private javax.swing.JRadioButton changeInCell; private javax.swing.JRadioButton changeInLibrary; private javax.swing.JCheckBox changeNodesWithArcs; private javax.swing.ButtonGroup changeOption; private javax.swing.JRadioButton changeSelected; private javax.swing.JButton done; private javax.swing.JCheckBox ignorePortNames; private javax.swing.JLabel jLabel1; private javax.swing.JComboBox librariesPopup; private javax.swing.JScrollPane listPane; private javax.swing.JCheckBox showCells; private javax.swing.JCheckBox showPrimitives; // End of variables declaration//GEN-END:variables }