Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: CellChangeJobs.java
*
* Copyright (c) 2006, 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;
import com.sun.electric.database.EditingPreferences;
import com.sun.electric.database.IdMapper;
import com.sun.electric.database.ImmutableArcInst;
import com.sun.electric.database.geometry.EGraphics;
import com.sun.electric.database.geometry.EPoint;
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.id.CellId;
import com.sun.electric.database.prototype.NodeProto;
import com.sun.electric.database.text.Name;
import com.sun.electric.database.topology.ArcInst;
import com.sun.electric.database.topology.Geometric;
import com.sun.electric.database.topology.NodeInst;
import com.sun.electric.database.topology.NodeInst.ExpansionState;
import com.sun.electric.database.topology.PortInst;
import com.sun.electric.database.variable.ElectricObject;
import com.sun.electric.database.variable.TextDescriptor;
import com.sun.electric.database.variable.UserInterface;
import com.sun.electric.technology.ArcProto;
import com.sun.electric.technology.technologies.Artwork;
import com.sun.electric.technology.technologies.Generic;
import com.sun.electric.tool.Job;
import com.sun.electric.tool.JobException;
import com.sun.electric.tool.user.ui.EditWindow;
import com.sun.electric.tool.user.ui.WindowContent;
import com.sun.electric.tool.user.ui.WindowFrame;
import com.sun.electric.util.math.FixpTransform;
import com.sun.electric.util.math.GenMath;
import com.sun.electric.util.math.Orientation;
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;
/**
* Class for Jobs that make changes to the cells.
*/
public class CellChangeJobs
{
// constructor, never used
private CellChangeJobs() {}
/****************************** DELETE A CELL ******************************/
/**
* Class to delete a cell in a new thread.
*/
public static class DeleteCell extends Job
{
Cell cell;
public DeleteCell(Cell cell)
{
super("Delete " + cell, User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
this.cell = cell;
startJob();
}
public boolean doIt() throws JobException
{
// check cell usage once more
if (cell.isInUse("delete", false, true)) return false;
cell.kill();
return true;
}
}
/**
* This class implement the command to delete a list of cells.
*/
public static class DeleteManyCells extends Job
{
private List cellsToDelete;
public DeleteManyCells(List cellsToDelete)
{
super("Delete Multiple Cells", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
this.cellsToDelete = cellsToDelete;
startJob();
}
public boolean doIt() throws JobException
{
// iteratively delete, allowing cells in use to be deferred
boolean didDelete = true;
while (didDelete)
{
didDelete = false;
for (int i=0; i cells;
public DeleteCellGroup(Cell.CellGroup group)
{
super("Delete Cell Group", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
cells = new ArrayList();
for(Iterator it = group.getCells(); it.hasNext(); )
{
cells.add(it.next());
}
startJob();
}
public boolean doIt() throws JobException
{
// for(Cell cell : cells)
// {
// // Doesn't check cells in the same group
// // check cell usage once more
// if (cell.isInUse("delete", false, false))
// return false;
// }
// Now real delete
for(Cell cell : cells)
{
cell.kill();
}
return true;
}
}
/**
* Class to rename a cell in a new thread.
*/
public static class RenameCellGroup extends Job
{
Cell cellInGroup;
String newName;
public RenameCellGroup(Cell cellInGroup, String newName)
{
super("Rename Cell Group", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
this.cellInGroup = cellInGroup;
this.newName = newName;
startJob();
}
public boolean doIt() throws JobException
{
// see if all cells in the group have the same name
boolean allSameName = true;
String lastName = null;
for(Iterator it = cellInGroup.getCellGroup().getCells(); it.hasNext(); )
{
String cellName = it.next().getName();
if (lastName != null && !lastName.equals(cellName))
{
allSameName = false;
break;
}
lastName = cellName;
}
List cells = new ArrayList();
for(Iterator it = cellInGroup.getCellGroup().getCells(); it.hasNext(); )
cells.add(it.next());
String newGroupCell = null;
for(Cell cell : cells)
{
if (allSameName)
{
cell.rename(newName, newName);
} else
{
if (newGroupCell == null)
{
System.out.println("Renaming is not possible because cells in group don't have same root name.");
System.out.println("'" + newName + "' was added as prefix.");
newGroupCell = newName + cell.getName();
}
cell.rename(newName+cell.getName(), newGroupCell);
}
}
return true;
}
}
/****************************** SHOW CELLS GRAPHICALLY ******************************/
/**
* This class implement the command to make a graph of the cells.
*/
public static class GraphCells extends Job
{
private static final double TEXTHEIGHT = 2;
private Cell top;
private Cell graphCell;
private static class GraphNode
{
String name;
int depth;
int clock;
double x, y;
double yoff;
NodeInst pin;
NodeInst topPin;
NodeInst botPin;
GraphNode main;
}
public GraphCells(Cell top)
{
super("Graph Cells", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
this.top = top;
startJob();
}
@Override
public boolean doIt() throws JobException
{
EditingPreferences ep = getEditingPreferences();
// create the graph cell
graphCell = Cell.newInstance(Library.getCurrent(), "CellStructure");
fieldVariableChanged("graphCell");
if (graphCell == null) return false;
if (graphCell.getNumVersions() > 1)
System.out.println("Creating new version of cell: " + graphCell.getName()); else
System.out.println("Creating cell: " + graphCell.getName());
// create GraphNodes for every cell and initialize the depth to -1
Map graphNodes = new HashMap();
for(Iterator it = Library.getLibraries(); it.hasNext(); )
{
Library lib = it.next();
if (lib.isHidden()) continue;
for(Iterator cIt = lib.getCells(); cIt.hasNext(); )
{
Cell cell = cIt.next();
GraphNode cgn = new GraphNode();
cgn.name = cell.describe(false);
cgn.depth = -1;
graphNodes.put(cell, cgn);
}
}
// find all top-level cells
int maxDepth = 0;
if (top != null)
{
GraphNode cgn = graphNodes.get(top);
cgn.depth = 0;
} else
{
for(Iterator cIt = Library.getCurrent().getCells(); cIt.hasNext(); )
{
Cell cell = cIt.next();
if (cell.getNumUsagesIn() == 0)
{
GraphNode cgn = graphNodes.get(cell);
cgn.depth = 0;
}
}
}
double xScale = 2.0 / 3.0;
double yScale = 20;
double yOffset = TEXTHEIGHT * 1.25;
double maxWidth = 0;
// now place all cells at their proper depth
boolean more = true;
while (more)
{
more = false;
for(Iterator it = Library.getLibraries(); it.hasNext(); )
{
Library lib = it.next();
if (lib.isHidden()) continue;
for(Iterator cIt = lib.getCells(); cIt.hasNext(); )
{
Cell cell = cIt.next();
GraphNode cgn = graphNodes.get(cell);
if (cgn.depth == -1) continue;
for(Iterator nIt = cell.getNodes(); nIt.hasNext(); )
{
NodeInst ni = nIt.next();
if (!ni.isCellInstance()) continue;
// ignore recursive references (showing icon in contents)
if (ni.isIconOfParent()) continue;
Cell sub = (Cell)ni.getProto();
GraphNode subCgn = graphNodes.get(sub);
if (subCgn.depth <= cgn.depth)
{
subCgn.depth = cgn.depth + 1;
if (subCgn.depth > maxDepth) maxDepth = subCgn.depth;
more = true;
}
Cell trueCell = sub.contentsView();
if (trueCell == null) continue;
GraphNode trueCgn = graphNodes.get(trueCell);
if (trueCgn.depth <= cgn.depth)
{
trueCgn.depth = cgn.depth + 1;
if (trueCgn.depth > maxDepth) maxDepth = trueCgn.depth;
more = true;
}
}
}
}
// add in any cells referenced from other libraries
if (!more && top == null)
{
for(Iterator cIt = Library.getCurrent().getCells(); cIt.hasNext(); )
{
Cell cell = cIt.next();
GraphNode cgn = graphNodes.get(cell);
if (cgn.depth >= 0) continue;
cgn.depth = 0;
more = true;
}
}
}
// now assign X coordinates to each graph node
maxDepth++;
double [] xval = new double[maxDepth];
double [] yoff = new double[maxDepth];
for(int i=0; i maxWidth) maxWidth = xval[cgn.depth];
cgn.y = cgn.depth;
cgn.yoff = 0;
}
// now center each row
for(Cell cell : graphNodes.keySet())
{
GraphNode cgn = graphNodes.get(cell);
if (cgn.depth == -1) continue;
if (xval[(int)cgn.y] < maxWidth)
{
double spread = maxWidth / xval[(int)cgn.y];
cgn.x = cgn.x * spread;
}
}
// generate accurate X/Y coordinates
for(Cell cell : graphNodes.keySet())
{
GraphNode cgn = graphNodes.get(cell);
if (cgn.depth == -1) continue;
double x = cgn.x; double y = cgn.y;
x = x * xScale;
y = -y * yScale + ((yoff[(int)cgn.y]++)%3) * yOffset;
cgn.x = x; cgn.y = y;
}
// make unattached cells sit with their contents view
if (top == null)
{
for(Iterator it = Library.getLibraries(); it.hasNext(); )
{
Library lib = it.next();
if (lib.isHidden()) continue;
for(Iterator cIt = lib.getCells(); cIt.hasNext(); )
{
Cell cell = cIt.next();
GraphNode cgn = graphNodes.get(cell);
if (cgn.depth != -1) continue;
if (cell.getNumUsagesIn() != 0 && !cell.isIcon() &&
cell.getView() != View.LAYOUTSKEL) continue;
Cell trueCell = graphMainView(cell);
if (trueCell == null) continue;
GraphNode trueCgn = graphNodes.get(trueCell);
if (trueCgn.depth == -1) continue;
cgn.pin = cgn.topPin = cgn.botPin = null;
cgn.main = trueCgn;
cgn.yoff += yOffset*2;
cgn.x = trueCgn.x;
cgn.y = trueCgn.y + trueCgn.yoff;
}
}
}
// write the header message
double xsc = maxWidth * xScale / 2;
NodeInst titleNi = NodeInst.newInstance(Generic.tech().invisiblePinNode, ep, new Point2D.Double(xsc, yScale), 0, 0, graphCell);
if (titleNi == null) return false;
String msg;
if (top != null) msg = "Structure below " + top; else
msg = "Structure of library " + Library.getCurrent().getName();
TextDescriptor td = ep.getNodeTextDescriptor().withRelSize(6);
titleNi.newVar(Artwork.ART_MESSAGE, msg, td);
// place the components
for(Cell cell : graphNodes.keySet())
{
GraphNode cgn = graphNodes.get(cell);
if (cgn.depth == -1) continue;
double x = cgn.x; double y = cgn.y;
cgn.pin = NodeInst.newInstance(Generic.tech().invisiblePinNode, ep, new Point2D.Double(x, y), 0, 0, graphCell);
if (cgn.pin == null) return false;
cgn.topPin = NodeInst.newInstance(Generic.tech().invisiblePinNode, ep, new Point2D.Double(x, y+TEXTHEIGHT/2), 0, 0, graphCell);
if (cgn.topPin == null) return false;
cgn.botPin = NodeInst.newInstance(Generic.tech().invisiblePinNode, ep, new Point2D.Double(x, y-TEXTHEIGHT/2), 0, 0, graphCell);
if (cgn.botPin == null) return false;
PortInst pinPi = cgn.pin.getOnlyPortInst();
PortInst toppinPi = cgn.botPin.getOnlyPortInst();
PortInst botPinPi = cgn.topPin.getOnlyPortInst();
ArcInst link1 = ArcInst.makeInstanceBase(Generic.tech().invisible_arc, ep, 0, toppinPi, pinPi);
ArcInst link2 = ArcInst.makeInstanceBase(Generic.tech().invisible_arc, ep, 0, pinPi, botPinPi);
link1.setRigid(true);
link2.setRigid(true);
link1.setHardSelect(true);
link2.setHardSelect(true);
cgn.topPin.setHardSelect();
cgn.botPin.setHardSelect();
// write the cell name in the node
TextDescriptor ctd = ep.getNodeTextDescriptor().withRelSize(2);
cgn.pin.newVar(Artwork.ART_MESSAGE, cgn.name, ctd);
}
// attach related components with rigid arcs
for(Cell cell : graphNodes.keySet())
{
GraphNode cgn = graphNodes.get(cell);
if (cgn.depth == -1) continue;
if (cgn.main == null) continue;
PortInst firstPi = cgn.pin.getOnlyPortInst();
ArcInst ai = ArcInst.makeInstanceBase(Artwork.tech().solidArc, ep, 0, firstPi, firstPi);
if (ai == null) return false;
ai.setRigid(true);
ai.setHardSelect(true);
// set an invisible color on the arc
ai.newVar(Artwork.ART_COLOR, new Integer(0), ep);
}
// build wires between the hierarchical levels
int clock = 0;
for(Iterator it = Library.getLibraries(); it.hasNext(); )
{
Library lib = it.next();
if (lib.isHidden()) continue;
for(Iterator cIt = lib.getCells(); cIt.hasNext(); )
{
Cell cell = cIt.next();
if (cell == graphCell) continue;
// always use the contents cell, not the icon
Cell trueCell = cell.contentsView();
if (trueCell == null) trueCell = cell;
GraphNode trueCgn = graphNodes.get(trueCell);
if (trueCgn.depth == -1) continue;
clock++;
for(Iterator nIt = trueCell.getNodes(); nIt.hasNext(); )
{
NodeInst ni = nIt.next();
if (!ni.isCellInstance()) continue;
// ignore recursive references (showing icon in contents)
if (ni.isIconOfParent()) continue;
Cell sub = (Cell)ni.getProto();
Cell truesubnp = sub.contentsView();
if (truesubnp == null) truesubnp = sub;
GraphNode trueSubCgn = graphNodes.get(truesubnp);
if (trueSubCgn.clock == clock) continue;
trueSubCgn.clock = clock;
// draw a line from cell "trueCell" to cell "truesubnp"
if (trueSubCgn.depth == -1) continue;
PortInst toppinPi = trueCgn.botPin.getOnlyPortInst();
PortInst niBotPi = trueSubCgn.topPin.getOnlyPortInst();
ArcInst ai = ArcInst.makeInstance(Artwork.tech().solidArc, ep, toppinPi, niBotPi);
if (ai == null) return false;
ai.setRigid(false);
ai.setFixedAngle(false);
ai.setSlidable(false);
ai.setHardSelect(true);
// set an appropriate color on the arc (red for jumps of more than 1 level of depth)
int color = EGraphics.BLUE;
if (trueCgn.y - trueSubCgn.y > yScale+yOffset+yOffset) color = EGraphics.RED;
ai.newVar(Artwork.ART_COLOR, new Integer(color), ep);
}
}
}
return true;
}
@Override
public void terminateOK()
{
// display the graph cell
UserInterface ui = Job.getUserInterface();
ui.displayCell(graphCell);
}
/**
* Method to find the main cell that "cell" is associated with in the graph. This code is
* essentially the same as "contentscell()" except that any original type is allowed.
* @return null if the cell is not associated.
*/
private Cell graphMainView(Cell cell)
{
// first check to see if there is a schematics link
Cell mainSchem = cell.getCellGroup().getMainSchematics();
if (mainSchem != null) return mainSchem;
// now check to see if there is any layout link
for(Iterator it = cell.getCellGroup().getCells(); it.hasNext(); )
{
Cell cellInGroup = it.next();
if (cellInGroup.getView() == View.LAYOUT) return cellInGroup;
}
// finally check to see if there is any "unknown" link
for(Iterator it = cell.getCellGroup().getCells(); it.hasNext(); )
{
Cell cellInGroup = it.next();
if (cellInGroup.getView() == View.UNKNOWN) return cellInGroup;
}
// no contents found
return null;
}
}
/****************************** SHOW LIBRARIES GRAPHICALLY ******************************/
/**
* This class implement the command to make a graph of the libraries.
*/
public static class GraphLibraries extends Job
{
private Cell graphCell;
private static class GraphNode
{
String name;
boolean topLibrary;
boolean leafLibrary;
double x, y;
NodeInst pin;
}
private static class GraphArc
{
GraphNode from;
GraphNode to;
boolean doubleHeaded;
}
public GraphLibraries()
{
super("Graph Libraries", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
startJob();
}
@Override
public boolean doIt() throws JobException
{
EditingPreferences ep = getEditingPreferences();
// create the graph cell
graphCell = Cell.newInstance(Library.getCurrent(), "LibraryStructure");
fieldVariableChanged("graphCell");
if (graphCell == null) return false;
if (graphCell.getNumVersions() > 1)
System.out.println("Creating new version of cell: " + graphCell.getName()); else
System.out.println("Creating cell: " + graphCell.getName());
// create GraphNodes for every library
Map graphNodes = new HashMap();
Map> libraryDependencies = new HashMap>();
for(Iterator it = Library.getLibraries(); it.hasNext(); )
{
Library lib = it.next();
if (lib.isHidden()) continue;
GraphNode cgn = new GraphNode();
cgn.name = lib.getName();
cgn.leafLibrary = true;
cgn.topLibrary = true;
graphNodes.put(lib, cgn);
for(Iterator cIt = lib.getCells(); cIt.hasNext(); )
{
Cell cell = cIt.next();
for(Iterator nIt = cell.getNodes(); nIt.hasNext(); )
{
NodeInst ni = nIt.next();
if (!ni.isCellInstance()) continue;
// ignore recursive references (showing icon in contents)
if (ni.isIconOfParent()) continue;
Library subLib = ((Cell)ni.getProto()).getLibrary();
if (subLib == lib) continue;
Set subLibs = libraryDependencies.get(lib);
if (subLibs == null) libraryDependencies.put(lib, subLibs = new HashSet());
subLibs.add(subLib);
cgn.leafLibrary = false;
}
}
}
// compute top libraries
for(Iterator it = Library.getLibraries(); it.hasNext(); )
{
Library lib = it.next();
GraphNode cgn = graphNodes.get(lib);
if (cgn == null) continue;
Set subLibs = libraryDependencies.get(lib);
if (subLibs == null) continue;
for(Library subLib : subLibs)
{
GraphNode subCGN = graphNodes.get(subLib);
if (subCGN != null) subCGN.topLibrary = false;
}
}
double radius = 50;
// count the number of each class of library
int numCentral = 0, numTop = 0, numLeaf = 0;
for(Library lib : graphNodes.keySet())
{
GraphNode cgn = graphNodes.get(lib);
if (cgn.topLibrary) numTop++; else
if (cgn.leafLibrary) numLeaf++; else
numCentral++;
}
// arrange the top and leaf libraries outside, the others in a circle
double curAngle = 0, curTop = 0, curLeaf = 0;
for(Library lib : graphNodes.keySet())
{
GraphNode cgn = graphNodes.get(lib);
if (cgn.topLibrary)
{
cgn.x = -radius + (radius*2/numTop*curTop) + (radius*2/(numTop+1));
cgn.y = radius * 1.25;
curTop++;
} else if (cgn.leafLibrary)
{
cgn.x = -radius + (radius*2/numLeaf*curLeaf) + (radius*2/(numLeaf+1));
cgn.y = -radius * 1.25;
curLeaf++;
} else
{
cgn.x = Math.cos(curAngle) * radius;
cgn.y = Math.sin(curAngle) * radius;
curAngle += Math.PI * 2 / numCentral;
}
}
// write the header message
NodeInst titleNi = NodeInst.newInstance(Generic.tech().invisiblePinNode, ep, new Point2D.Double(0, radius*1.5), 0, 0, graphCell);
if (titleNi == null) return false;
TextDescriptor td = ep.getNodeTextDescriptor().withRelSize(6);
titleNi.newVar(Artwork.ART_MESSAGE, "Structure of library dependencies", td);
// make a list of all arcs in the graph
List allArcs = new ArrayList();
for(Iterator it = Library.getLibraries(); it.hasNext(); )
{
Library lib = it.next();
if (lib.isHidden()) continue;
GraphNode trueCgn = graphNodes.get(lib);
Set subLibs = libraryDependencies.get(lib);
if (subLibs == null) continue;
for(Library subLib : subLibs)
{
GraphNode trueSubCgn = graphNodes.get(subLib);
boolean found = false;
for(GraphArc ga : allArcs)
{
if (ga.from == trueSubCgn && ga.to == trueCgn)
{
found = true;
ga.doubleHeaded = true;
break;
}
}
if (found) continue;
GraphArc ga = new GraphArc();
ga.from = trueCgn;
ga.to = trueSubCgn;
ga.doubleHeaded = false;
allArcs.add(ga);
}
}
// place the components
for(Library lib : graphNodes.keySet())
{
GraphNode cgn = graphNodes.get(lib);
double x = cgn.x; double y = cgn.y;
cgn.pin = NodeInst.newInstance(Generic.tech().invisiblePinNode, ep, new Point2D.Double(x, y), 0, 0, graphCell);
if (cgn.pin == null) return false;
// write the cell name in the node
TextDescriptor ctd = ep.getNodeTextDescriptor().withRelSize(2);
if (!cgn.leafLibrary && !cgn.topLibrary)
{
if (x > Math.abs(y))
{
// on the right
ctd = ctd.withPos(TextDescriptor.Position.UPRIGHT);
} else if (x < -Math.abs(y))
{
// on the left
ctd = ctd.withPos(TextDescriptor.Position.UPLEFT);
} else if (y > Math.abs(x))
{
// on the top
ctd = ctd.withPos(TextDescriptor.Position.UPRIGHT).withRotation(TextDescriptor.Rotation.getRotation(90));
} else
{
// on the bottom
ctd = ctd.withPos(TextDescriptor.Position.UPRIGHT).withRotation(TextDescriptor.Rotation.getRotation(270));
}
}
cgn.pin.setName(cgn.name);
cgn.pin.setTextDescriptor(NodeInst.NODE_NAME, ctd);
}
// build wires between the hierarchical levels
for(GraphArc ga : allArcs)
{
GraphNode trueCgn = ga.from;
GraphNode trueSubCgn = ga.to;
// draw a line from cell "trueCell" to cell "truesubnp"
PortInst toppinPi = trueCgn.pin.getOnlyPortInst();
PortInst niBotPi = trueSubCgn.pin.getOnlyPortInst();
ArcInst ai = ArcInst.makeInstance(Artwork.tech().solidArc, ep, toppinPi, niBotPi);
if (ai == null) return false;
ai.setRigid(false);
ai.setFixedAngle(false);
ai.setSlidable(false);
// set an appropriate color on the arc
int color = EGraphics.RED;
if (ga.doubleHeaded) color = EGraphics.LRED;
if (trueCgn.topLibrary) color = EGraphics.BLUE; else
if (trueSubCgn.leafLibrary) color = EGraphics.GREEN;
ai.newVar(Artwork.ART_COLOR, new Integer(color), ep);
String msg = trueCgn.name + "-USES-" + trueSubCgn.name;
if (ga.doubleHeaded) msg = trueCgn.name + "-CO-DEPENDS-ON-" + trueSubCgn.name;
ai.setName(msg, ep);
TextDescriptor atd = ep.getArcTextDescriptor().withDisplay(false);
ai.setTextDescriptor(ArcInst.ARC_NAME, atd);
}
return true;
}
@Override
public void terminateOK()
{
// display the graph cell
UserInterface ui = Job.getUserInterface();
ui.displayCell(graphCell);
}
}
/****************************** EXTRACT CELL INSTANCES ******************************/
/**
* This class implements the command to package circuitry into a new cell.
*/
public static class PackageCell extends Job
{
Cell curCell;
Set whatToPackage;
String newCellName;
private Set expandedNodes = new HashSet();
private ExpansionState expansionState;
// private IconParameters iconParameters = IconParameters.makeInstance(true);
public PackageCell(Cell curCell, Set whatToPackage, String newCellName)
{
super("Package Cell", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
this.curCell = curCell;
this.whatToPackage = whatToPackage;
this.newCellName = newCellName;
expansionState = new ExpansionState(curCell, ExpansionState.JUSTTHISCELL);
startJob();
}
@Override
public boolean doIt() throws JobException
{
EditingPreferences ep = getEditingPreferences();
// create the new cell
Cell cell = Cell.makeInstance(ep, Library.getCurrent(), newCellName);
if (cell == null) return false;
// copy the nodes into the new cell
Map newNodes = new HashMap();
for(Geometric look : whatToPackage)
{
if (!(look instanceof NodeInst)) continue;
NodeInst ni = (NodeInst)look;
String name = null;
Name oldName = ni.getNameKey();
if (!oldName.isTempname()) name = oldName.toString();
NodeInst newNi = NodeInst.makeInstance(ni.getProto(), ep, new Point2D.Double(ni.getAnchorCenterX(), ni.getAnchorCenterY()),
ni.getXSize(), ni.getYSize(), cell, ni.getOrient(), name);
if (newNi == null) return false;
newNodes.put(ni, newNi);
newNi.copyStateBits(ni);
if (expansionState.isExpanded(ni))
expandedNodes.add(newNi);
newNi.copyVarsFrom(ni);
newNi.copyTextDescriptorFrom(ni, NodeInst.NODE_NAME);
// make ports where this nodeinst has them
for(Iterator it = ni.getExports(); it.hasNext(); )
{
Export pp = it.next();
PortInst pi = newNi.findPortInstFromProto(pp.getOriginalPort().getPortProto());
Export newPp = Export.newInstance(cell, pi, pp.getName(), ep, pp.getCharacteristic());
if (newPp != null)
{
newPp.copyTextDescriptorFrom(pp, Export.EXPORT_NAME);
newPp.copyVarsFrom(pp);
}
}
}
// copy the arcs into the new cell
for(Geometric look : whatToPackage)
{
if (!(look instanceof ArcInst)) continue;
ArcInst ai = (ArcInst)look;
NodeInst niTail = newNodes.get(ai.getTailPortInst().getNodeInst());
NodeInst niHead = newNodes.get(ai.getHeadPortInst().getNodeInst());
if (niTail == null || niHead == null) continue;
PortInst piTail = niTail.findPortInstFromProto(ai.getTailPortInst().getPortProto());
PortInst piHead = niHead.findPortInstFromProto(ai.getHeadPortInst().getPortProto());
String name = null;
Name oldName = ai.getNameKey();
if (!oldName.isTempname()) name = oldName.toString();
ArcInst newAi = ArcInst.makeInstanceBase(ai.getProto(), ep, ai.getLambdaBaseWidth(), piHead, piTail, ai.getHeadLocation(),
ai.getTailLocation(), name);
if (newAi == null) return false;
newAi.copyPropertiesFrom(ai);
}
System.out.println("Cell " + cell.describe(true) + " created");
fieldVariableChanged("expandedNodes");
return true;
}
@Override
public void terminateOK() {
for (NodeInst ni: expandedNodes)
ni.setExpanded(true);
}
}
/**
* This class implement the command to extract the contents of cell instances.
*/
public static class ExtractCellInstances extends Job
{
private Cell cell;
private List nodes;
private boolean copyExports;
private boolean fromRight;
private int depth;
private Set expandedNodes = new HashSet();
private boolean startNow;
private ExpansionState expansionState;
public ExtractCellInstances(Cell cell, List highlighted, int depth, boolean copyExports,
boolean fromRight, boolean startNow)
{
super("Extract Cell Instances", User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
this.cell = cell;
this.nodes = highlighted;
this.copyExports = copyExports;
this.fromRight = fromRight;
this.depth = depth;
this.startNow = startNow;
this.expansionState = new ExpansionState(cell, ExpansionState.JUSTTHISHIERARCHY);
if (!startNow)
startJob();
else
{
try {doIt(); } catch (Exception e) {e.printStackTrace();}
}
}
@Override
public boolean doIt() throws JobException
{
EditingPreferences ep = getEditingPreferences();
doArbitraryExtraction(cell, expansionState, expandedNodes, nodes, copyExports, depth, fromRight, ep);
if (!startNow)
fieldVariableChanged("expandedNodes");
return true;
}
@Override
public void terminateOK() {
for (NodeInst ni: expandedNodes)
ni.setExpanded(true);
}
}
private static void doArbitraryExtraction(Cell cell, ExpansionState expansionState, Set expandedNodes,
List nodes, boolean copyExports, int depth, boolean fromRight, EditingPreferences ep)
{
Job.getUserInterface().startProgressDialog("Extracting " + nodes.size() + " cells", null);
Map> newNodes = new HashMap>();
int done = 0;
Set nodesToKill = new HashSet();
List exportsToCopy = new ArrayList();
for(NodeInst ni : nodes)
{
if (!ni.isCellInstance()) continue;
Map portMap = new HashMap();
extractOneLevel(cell, expansionState, expandedNodes, ni, GenMath.MATID, portMap, 1, depth, fromRight, ep);
newNodes.put(ni, portMap);
for (Iterator it = ni.getExports(); it.hasNext(); )
exportsToCopy.add(it.next());
done++;
Job.getUserInterface().setProgressValue(done * 100 / nodes.size());
nodesToKill.add(ni);
}
// replace arcs to the cell and exports on the cell
Job.getUserInterface().setProgressNote("Replacing top-level arcs and exports");
replaceExtractedArcs(cell, cell, newNodes, GenMath.MATID, fromRight, ep);
// replace the exports if needed
if (copyExports)
{
for(Export pp : exportsToCopy)
{
PortInst oldPi = pp.getOriginalPort();
Map nodePortMap = newNodes.get(oldPi.getNodeInst());
if (nodePortMap == null) continue;
PortInst newPi = nodePortMap.get(oldPi);
if (newPi == null)
{
pp.kill();
continue;
}
pp.move(newPi);
}
}
// delete original nodes
cell.killNodes(nodesToKill);
Job.getUserInterface().stopProgressDialog();
}
private static void extractOneLevel(Cell cell, ExpansionState expansionState, Set expandedNodes,
NodeInst topno, FixpTransform prevTrans, Map portMap, int curDepth, int totDepth, boolean fromRight,
EditingPreferences ep)
{
Map> newNodes = new HashMap>();
// see if there are already Essential Bounds nodes in the top cell
boolean hasEssentialBounds = false;
for(Iterator it = cell.getNodes(); it.hasNext(); )
{
NodeInst ni = it.next();
NodeProto np = ni.getProto();
if (np == Generic.tech().essentialBoundsNode) { hasEssentialBounds = true; break; }
}
// make transformation matrix for this cell
Cell subCell = (Cell)topno.getProto();
FixpTransform localTrans = topno.translateOut(topno.rotateOut());
localTrans.preConcatenate(prevTrans);
for(Iterator it = subCell.getNodes(); it.hasNext(); )
{
NodeInst ni = it.next();
Map subPortMap = new HashMap();
newNodes.put(ni, subPortMap);
// do not extract "cell center" primitives
NodeProto np = ni.getProto();
if (np == Generic.tech().cellCenterNode) continue;
// do not extract "essential bounds" primitives if they exist in the top-level cell
if (np == Generic.tech().essentialBoundsNode && hasEssentialBounds) continue;
boolean extractCell = false;
if (ni.isCellInstance() && curDepth < totDepth) extractCell = true;
if (extractCell)
{
extractOneLevel(cell, expansionState, expandedNodes, ni, localTrans, subPortMap, curDepth+1, totDepth, fromRight, ep);
// add to the portmap
for(Iterator eIt = ni.getExports(); eIt.hasNext(); )
{
Export e = eIt.next();
PortInst fromPi = topno.findPortInstFromProto(e);
PortInst toPi = subPortMap.get(e.getOriginalPort());
portMap.put(fromPi, toPi);
}
} else
{
String name = null;
if (ni.isUsernamed())
name = ElectricObject.uniqueObjectName(ni.getName(), cell, NodeInst.class, false, fromRight);
Orientation orient = topno.getOrient().concatenate(ni.getOrient());
Point2D pt = new Point2D.Double(ni.getAnchorCenterX(), ni.getAnchorCenterY());
FixpTransform instTrans = ni.rotateOut(localTrans);
instTrans.transform(pt, pt);
NodeInst newNi = NodeInst.makeInstance(np, ep, pt, ni.getXSize(), ni.getYSize(), cell, orient, name);
if (newNi == null) continue;
newNi.copyTextDescriptorFrom(ni, NodeInst.NODE_NAME);
newNi.copyStateBits(ni);
if (expansionState.isExpanded(ni))
expandedNodes.add(newNi);
newNi.copyVarsFrom(ni);
// add ports to the new node's portmap
for(Iterator pIt = ni.getPortInsts(); pIt.hasNext(); )
{
PortInst oldPi = pIt.next();
PortInst newPi = newNi.findPortInstFromProto(oldPi.getPortProto());
subPortMap.put(oldPi, newPi);
}
// add exports to the parent portmap
for(Iterator eIt = ni.getExports(); eIt.hasNext(); )
{
Export e = eIt.next();
PortInst fromPi = topno.findPortInstFromProto(e);
PortInst toPi = newNi.findPortInstFromProto(e.getOriginalPort().getPortProto());
portMap.put(fromPi, toPi);
}
}
}
replaceExtractedArcs(cell, subCell, newNodes, localTrans, fromRight, ep);
}
private static void replaceExtractedArcs(Cell destCell, Cell cell, Map> nodeMaps,
FixpTransform trans, boolean fromRight, EditingPreferences ep)
{
for(Iterator it = cell.getArcs(); it.hasNext(); )
{
ArcInst ai = it.next();
PortInst oldHeadPi = ai.getHeadPortInst();
NodeInst headNi = oldHeadPi.getNodeInst();
Map headMap = nodeMaps.get(headNi);
PortInst oldTailPi = ai.getTailPortInst();
NodeInst tailNi = oldTailPi.getNodeInst();
Map tailMap = nodeMaps.get(tailNi);
if (headMap == null && tailMap == null) continue;
PortInst newHeadPi = oldHeadPi;
if (headMap != null)
{
newHeadPi = headMap.get(oldHeadPi);
if (newHeadPi == null)
{
System.out.println("Warning: arc " + ai.describe(false) + " in cell " + cell.describe(false) +
" is missing head connectivity information");
continue;
}
}
PortInst newTailPi = oldTailPi;
if (tailMap != null)
{
newTailPi = tailMap.get(oldTailPi);
if (newTailPi == null)
{
System.out.println("Warning: arc " + ai.describe(false) + " in cell " + cell.describe(false) +
" is missing tail connectivity information");
continue;
}
}
if (newHeadPi == null || newTailPi == null)
{
System.out.println("Warning: cannot reconnect arc in cell " + cell.describe(false) +
" from " + oldHeadPi + " to " + oldTailPi);
continue;
}
Point2D headLoc = new Point2D.Double(ai.getHeadLocation().getX(), ai.getHeadLocation().getY());
trans.transform(headLoc, headLoc);
Point2D tailLoc = new Point2D.Double(ai.getTailLocation().getX(), ai.getTailLocation().getY());
trans.transform(tailLoc, tailLoc);
ArcProto ap = ai.getProto();
String name = null;
if (ai.isUsernamed())
name = ElectricObject.uniqueObjectName(ai.getName(), cell, ArcInst.class, false, fromRight);
ImmutableArcInst a = ai.getD();
TextDescriptor nameDescriptor = a.nameDescriptor;
if (nameDescriptor == null) {
nameDescriptor = ep.getArcTextDescriptor();
}
ArcInst newAi = ArcInst.newInstanceNoCheck(destCell, ap, name, nameDescriptor,
newHeadPi, newTailPi, EPoint.snap(headLoc), EPoint.snap(tailLoc), a.getGridExtendOverMin(), a.getAngle(), a.flags);
if (newAi == null)
{
System.out.println("Error: arc " + ai.describe(false) + " in cell " + cell.describe(false) +
" was not extracted");
continue;
}
newAi.copyPropertiesFrom(ai);
}
}
/****************************** MAKE A NEW VERSION OF A CELL ******************************/
/**
* This class implement the command to make a new version of a cell.
*/
public static class NewCellVersion extends Job
{
private Cell cell;
private Cell newVersion;
private Map newCells = new HashMap();
public NewCellVersion(Cell cell)
{
super("Create new Version of " + cell, User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
this.cell = cell;
startJob();
}
@Override
public boolean doIt() throws JobException
{
newVersion = cell.makeNewVersion();
if (newVersion == null) return false;
newCells.put(cell.getId(), newVersion);
fieldVariableChanged("newVersion");
return true;
}
@Override
public void terminateOK()
{
if (newVersion == null) return;
// update cell expansion information
copyExpandedStatus(newCells);
// change the display of old versions to the new one
for(Iterator it = WindowFrame.getWindows(); it.hasNext(); )
{
WindowFrame wf = it.next();
WindowContent content = wf.getContent();
if (content == null) continue;
if (content.getCell() == cell)
wf.setCellWindow(newVersion, null);
}
EditWindow.repaintAll();
System.out.println("Created new version: "+newVersion+", old version renamed to "+cell);
}
}
/****************************** MAKE A COPY OF A CELL ******************************/
/**
* This class implement the command to duplicate a cell.
*/
public static class DuplicateCell extends Job
{
private Cell cell;
private Library destLib;
private String newName;
private boolean entireGroup;
private Cell dupCell;
private boolean startNow;
private Map newCells = new HashMap();
public DuplicateCell(Cell cell, String newName, Library lib, boolean entireGroup, boolean startN)
{
super("Duplicate " + cell, User.getUserTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
this.cell = cell;
this.newName = newName;
this.destLib = lib;
this.entireGroup = entireGroup;
this.startNow = startN;
if (startNow)
{
// mainly due to regressions
try {doIt(); } catch (Exception e) {e.printStackTrace();}
}
else
startJob();
}
@Override
public boolean doIt() throws JobException
{
EditingPreferences ep = getEditingPreferences();
String newCellName = newName + cell.getView().getAbbreviationExtension();
dupCell = Cell.copyNodeProto(cell, destLib, newCellName, false);
if (dupCell == null) {
System.out.println("Could not duplicate "+cell);
return false;
}
newCells.put(cell.getId(), dupCell);
if (!startNow) {
fieldVariableChanged("newCells");
fieldVariableChanged("dupCell");
}
System.out.println("Duplicated cell "+cell+". New cell is "+dupCell+".");
// examine all other cells in the group
List othersInGroup = new ArrayList();
for(Iterator it = cell.getCellGroup().getCells(); it.hasNext(); ) othersInGroup.add(it.next());
for(Cell otherCell : othersInGroup)
{
if (otherCell == cell) continue;
// When copy a schematic, we should copy the icon if entireGroup == false
if (!entireGroup && !(cell.isSchematic() && otherCell.isIcon())) continue;
Cell copyCell = Cell.copyNodeProto(otherCell, otherCell.getLibrary(),
newName + otherCell.getView().getAbbreviationExtension(), false);
if (copyCell == null)
{
System.out.println("Could not duplicate cell "+otherCell);
break;
}
newCells.put(otherCell.getId(), copyCell);
System.out.println(" Also duplicated cell "+otherCell+". New cell is "+copyCell+".");
}
// if icon of cell is present, replace old icon with new icon in new schematics cell
for(CellId oldCellId : newCells.keySet())
{
Cell newCell = newCells.get(oldCellId);
if (!newCell.isSchematic()) continue;
List replaceThese = new ArrayList();
for (Iterator it = newCell.getNodes(); it.hasNext(); )
{
NodeInst ni = it.next();
Cell replaceCell = newCells.get(ni.getProto().getId());
if (replaceCell != null) replaceThese.add(ni);
}
for(NodeInst ni : replaceThese)
{
// replace old icon(s) in duplicated cell
Cell replaceCell = newCells.get(ni.getProto().getId());
ni.replace(replaceCell, ep, true, true);
}
}
return true;
}
@Override
public void terminateOK()
{
// update cell expansion information
copyExpandedStatus(newCells);
// change the display of old cell to the new one
WindowFrame curWf = WindowFrame.getCurrentWindowFrame();
if (curWf != null)
{
WindowContent content = curWf.getContent();
if (content != null && content.getCell() == cell)
{
curWf.setCellWindow(dupCell, null);
return;
}
}
// current cell was not duplicated: see if any displayed cell is
for(Iterator it = WindowFrame.getWindows(); it.hasNext(); )
{
WindowFrame wf = it.next();
WindowContent content = wf.getContent();
if (content != null && content.getCell() == cell)
{
curWf.setCellWindow(dupCell, null);
return;
}
}
}
}
/**
* Copy expanded status in client database after some cells were copied or moved in server database
* @param newCells map from old to new cells.
*/
public static void copyExpandedStatus(Map newCells)
{
for (Map.Entry e: newCells.entrySet())
{
CellId oldCellId = e.getKey();
Cell newCell = e.getValue();
Cell oldCell = newCell.getDatabase().getCell(oldCellId);
if (oldCell == null) continue;
for (Iterator it = oldCell.getNodes(); it.hasNext(); )
{
NodeInst oldNi = it.next();
if (!oldNi.isCellInstance()) continue;
NodeInst newNi = newCell.findNode(oldNi.getName());
if (newNi == null) continue;
newNi.setExpanded(oldNi.isExpanded());
}
}
}
/****************************** COPY CELLS ******************************/
/**
* Method to recursively copy cells between libraries.
* @param fromCells the original cells being copied.
* @param toLib the destination library to copy the cell.
* @param verbose true to display extra information.
* @param move true to move instead of copy.
* @param allRelatedViews true to copy all related views (schematic cell with layout, etc.)
* If false, only schematic/icon relations are copied.
* @param copySubCells true to recursively copy sub-cells. If true, "useExisting" must be true.
* @param useExisting true to use any existing cells in the destination library
* instead of creating a cross-library reference. False to copy everything needed.
* @param ep EditingPreferences
* @return address of a copied cell (null on failure).
*/
public static IdMapper copyRecursively(List fromCells, Library toLib, boolean verbose, boolean move,
boolean allRelatedViews, boolean copySubCells, boolean useExisting, Map newCells, EditingPreferences ep)
{
IdMapper idMapper = new IdMapper();
Cell.setAllowCircularLibraryDependences(true);
try {
Map> existing = new HashMap>();
for(Cell fromCell : fromCells)
{
Cell copiedCell = copyRecursively(fromCell, toLib, verbose, move, "", true,
allRelatedViews, allRelatedViews, copySubCells, useExisting, existing, idMapper, newCells, ep);
if (copiedCell == null) break;
}
} finally {
Cell.setAllowCircularLibraryDependences(false);
}
return idMapper;
}
/**
* Method to recursively copy cells between libraries.
* @param fromCell the original cell being copied.
* @param toLib the destination library to copy the cell.
* @param verbose true to display extra information.
* @param move true to move instead of copy.
* @param subDescript a String describing the nature of this copy (empty string initially).
* @param schematicRelatedView true to copy a schematic related view. Typically this is true,
* meaning that if copying an icon, also copy the schematic. If already copying the example icon,
* this is set to false so that we don't get into a loop.
* @param allRelatedViews true to copy all related views (schematic cell with layout, etc.)
* If false, only schematic/icon relations are copied.
* @param allRelatedViewsThisLevel true to copy related views for this
* level of invocation only (but further recursion will use "allRelatedViews").
* @param copySubCells true to recursively copy sub-cells. If true, "useExisting" must be true.
* @param useExisting true to use any existing cells in the destination library
* instead of creating a cross-library reference. False to copy everything needed.
* @param existing a map that disambiguates cell names when they clash in different original libraries.
* The main key is an old cell name, and the value for that key is a map of library names to new cell names.
* So, for example, if libraries "A" and "B" both have a cell called "X", then existing.get("X").get("A") is "X" but
* existing.get(X").get("B") is "X_1" which disambiguates the cell names in the destination library.
* @param idMapper mapper which handles renamed cells
* @param newCells mapper which handles both copied and renamed cells
* @param ep EditingPreferences
*/
private static Cell copyRecursively(Cell fromCell, Library toLib, boolean verbose, boolean move, String subDescript,
boolean schematicRelatedView, boolean allRelatedViews, boolean allRelatedViewsThisLevel, boolean copySubCells,
boolean useExisting, Map> existing, IdMapper idMapper, Map newCells, EditingPreferences ep)
{
// check for sensibility
if (copySubCells && !useExisting)
System.out.println("Cross-library copy warning: It makes no sense to copy subcells but not use them");
// see if the cell is already there
String toName = fromCell.getName();
View toView = fromCell.getView();
Cell copiedCell = inDestLib(fromCell, existing, toLib);
if (copiedCell != null)
return copiedCell;
// copy subcells
if (copySubCells || fromCell.isSchematic())
{
boolean found = true;
while (found)
{
found = false;
for(Iterator it = fromCell.getNodes(); it.hasNext(); )
{
NodeInst ni = it.next();
if (!copySubCells && !ni.isIconOfParent()) continue;
if (!ni.isCellInstance()) continue;
Cell cell = (Cell)ni.getProto();
// allow cross-library references to stay
if (cell.getLibrary() == toLib) continue;
// see if the cell is already there
if (inDestLib(cell, existing, toLib) != null) continue;
// do not copy subcell if it exists already (and was not copied by this operation)
if (useExisting && !copySubCells)
{
if (toLib.findNodeProto(cell.noLibDescribe()) != null) continue;
}
// copy subcell if not already there
boolean doCopySchematicView = true;
if (ni.isIconOfParent()) doCopySchematicView = false;
Cell oNp = copyRecursively(cell, toLib, verbose,
move, "subcell ", doCopySchematicView, allRelatedViews, allRelatedViewsThisLevel,
copySubCells, useExisting, existing, idMapper, newCells, ep);
if (oNp == null)
{
if (move) System.out.println("Move of sub" + cell + " failed"); else
System.out.println("Copy of sub" + cell + " failed");
return null;
}
found = true;
break;
}
}
}
// see if copying related views
if (!allRelatedViewsThisLevel)
{
// not copying related views: just copy schematic if this was icon
if (toView == View.ICON && schematicRelatedView /*&& move*/ )
{
// now copy the schematics
boolean found = true;
while (found)
{
found = false;
assert fromCell.isLinked();
for(Iterator it = fromCell.getCellGroup().getCells(); it.hasNext(); )
{
Cell np = it.next();
if (!np.isSchematic()) continue;
// see if the cell is already there
if (inDestLib(np, existing, toLib) != null) continue;
// copy equivalent view if not already there
Cell oNp = copyRecursively(np, toLib, verbose,
move, "schematic view ", true, allRelatedViews, false, copySubCells, useExisting, existing, idMapper, newCells, ep);
if (oNp == null)
{
if (move) System.out.println("Move of schematic view " + np + " failed"); else
System.out.println("Copy of schematic view " + np + " failed");
return null;
}
found = true;
break;
}
if (!fromCell.isLinked())
return inDestLib(fromCell, existing, toLib);
}
}
} else
{
// first copy the icons
boolean found = true;
Cell fromCellWalk = fromCell;
while (found)
{
found = false;
for(Iterator it = fromCellWalk.getCellGroup().getCells(); it.hasNext(); )
{
Cell np = it.next();
if (!np.isIcon()) continue;
// see if the cell is already there
if (inDestLib(np, existing, toLib) != null) continue;
// copy equivalent view if not already there
Cell oNp = copyRecursively(np, toLib, verbose,
move, "alternate view ", true, allRelatedViews, false, copySubCells, useExisting, existing, idMapper, newCells, ep);
if (oNp == null)
{
if (move) System.out.println("Move of alternate view " + np + " failed"); else
System.out.println("Copy of alternate view " + np + " failed");
return null;
}
found = true;
break;
}
}
// now copy the rest
found = true;
while (found)
{
found = false;
Cell.CellGroup fromCellWalkGrp = fromCellWalk.getCellGroup();
if (fromCellWalkGrp == null) continue; // grp of given cell was moved?
for(Iterator it = fromCellWalkGrp.getCells(); it.hasNext(); )
{
Cell np = it.next();
if (np.isIcon()) continue;
// see if the cell is already there
if (inDestLib(np, existing, toLib) != null) continue;
// copy equivalent view if not already there
Cell oNp = copyRecursively(np, toLib, verbose,
move, "alternate view ", true, allRelatedViews, false, copySubCells, useExisting, existing, idMapper, newCells, ep);
if (oNp == null)
{
if (move) System.out.println("Move of alternate view " + np + " failed"); else
System.out.println("Copy of alternate view " + np + " failed");
return null;
}
found = true;
break;
}
}
}
// see if the cell is NOW there
copiedCell = inDestLib(fromCell, existing, toLib);
if (copiedCell != null) return copiedCell;
// get the proper cell name to use in the destination library
Map libToNameMap = existing.get(fromCell.getName());
if (libToNameMap == null)
{
libToNameMap = new HashMap();
existing.put(fromCell.getName(), libToNameMap);
}
String newName = libToNameMap.get(fromCell.getLibrary().getName());
if (newName == null)
{
for(int i=0; i<1000; i++)
{
newName = toName;
if (i > 0) newName += "_" + i;
if (!libToNameMap.values().contains(newName)) break;
}
libToNameMap.put(fromCell.getLibrary().getName(), newName);
}
newName += ";" + fromCell.getVersion();
if (toView.getAbbreviation().length() > 0)
newName += toView.getAbbreviationExtension();
Cell newFromCell = Cell.copyNodeProto(fromCell, toLib, newName, useExisting, existing);
if (newFromCell == null)
{
System.out.println("Copy of " + subDescript + fromCell + " failed");
return null;
}
// Message before the delete!!
if (verbose)
{
if (fromCell.getLibrary() != toLib)
{
String msg = "";
if (move) msg += "Moved "; else
msg += "Copied ";
msg += subDescript + fromCell.libDescribe() + " to " + toLib;
System.out.println(msg);
} else
{
System.out.println("Copied " + subDescript + newFromCell);
}
}
// if moving, adjust pointers and kill original cell
if (move)
{
// now replace old instances with the moved one
for(Iterator it = Library.getLibraries(); it.hasNext(); )
{
Library lib = it.next();
for(Iterator cIt = lib.getCells(); cIt.hasNext(); )
{
Cell np = cIt.next();
boolean found = true;
while (found)
{
found = false;
for(Iterator nIt = np.getNodes(); nIt.hasNext(); )
{
NodeInst ni = nIt.next();
if (ni.getProto() == fromCell)
{
NodeInst replacedNi = ni.replace(newFromCell, ep, false, false);
if (replacedNi == null)
{
System.out.println("Error moving " + ni + " in " + np);
found = false;
}
else
found = true;
break;
}
}
}
}
}
idMapper.moveCell(fromCell.backup(), newFromCell.getId());
fromCell.kill();
}
if (newCells != null) {
newCells.put(fromCell.getId(), newFromCell);
}
return newFromCell;
}
/**
* Method to tell whether a cell exists in the destination library.
* @param cell the Cell in question.
* @param existing a map that disambiguates cell names when they clash in different original libraries.
* The main key is an old cell name, and the value for that key is a map of library names to new cell names.
* So, for example, if libraries "A" and "B" both have a cell called "X", then existing.get("X").get("A") is "X" but
* existing.get(X").get("B") is "X_1" which disambiguates the cell names in the destination library.
* @param destLib the destination library being searched.
* @return a Cell from the destination library that matches the Cell being searched (null if none).
*/
private static Cell inDestLib(Cell cell, Map> existing, Library destLib)
{
Map libToNameMap = existing.get(cell.getName());
if (libToNameMap == null) return null;
String newCellName = libToNameMap.get(cell.getLibrary().getName());
if (newCellName == null) return null;
Cell copiedCell = destLib.findNodeProto(newCellName + ";" + cell.getVersion() + cell.getView().getAbbreviationExtension());
return copiedCell;
}
}