/* -*- tab-width: 4 -*- * * Electric(tm) VLSI Design System * * File: PortInst.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.database.topology; import com.sun.electric.database.ImmutablePortInst; import com.sun.electric.database.geometry.Poly; import com.sun.electric.database.geometry.EPoint; import com.sun.electric.database.hierarchy.Cell; import com.sun.electric.database.hierarchy.EDatabase; import com.sun.electric.database.hierarchy.Export; import com.sun.electric.database.prototype.PortProto; import com.sun.electric.database.text.Name; import com.sun.electric.database.variable.EditWindow0; import com.sun.electric.database.variable.ElectricObject; import com.sun.electric.database.variable.Variable; import java.awt.geom.Rectangle2D; import java.io.InvalidObjectException; import java.io.NotSerializableException; import java.io.ObjectStreamException; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; /** * The PortInst class represents an instance of a Port. It is the * combination of a NodeInst and a PortProto. * <P> * This class is thread-safe. */ public class PortInst extends ElectricObject { // ------------------------ private data ------------------------ private final NodeInst nodeInst; private final PortProto portProto; // -------------------protected or private methods --------------- private PortInst(PortProto portProto, NodeInst nodeInst) { this.portProto = portProto; this.nodeInst = nodeInst; } private Object writeReplace() throws NotSerializableException { if (!isLinked()) { throw new NotSerializableException(this + " not linked"); } return this; } private Object readResolve() throws ObjectStreamException { if (nodeInst.getProto() != portProto.getParent()) { throw new InvalidObjectException("PortInst"); } PortInst pi = nodeInst.findPortInstFromProto(portProto); if (pi == null) { throw new InvalidObjectException("PortInst"); } return pi; } /** * Returns persistent data of this ElectricObject with Variables. * @return persistent data of this ElectricObject. */ @Override public ImmutablePortInst getD() { return nodeInst.getD().getPortInst(portProto.getId()); } /** * Method to add a Variable on this PortInst. * It may add repaired copy of this Variable in some cases. * @param var Variable to add. */ public void addVar(Variable var) { nodeInst.addVar(portProto.getId(), var); } /** * Method to delete a Variable from this PortInst. * @param key the key of the Variable to delete. */ public void delVar(Variable.Key key) { nodeInst.delVar(portProto.getId(), key); } /** * Method to delete all Variables of this PortInst. */ public void delVars() { nodeInst.delVars(portProto.getId()); assert getNumVariables() == 0; } // ------------------------ public methods ------------------------- /** * Method to create a PortInst object. * @param portProto the PortProto on the prototype of the NodeInst. * @param nodeInst the NodeInst that owns the port. * @return the newly created PortInst. */ public static PortInst newInstance(PortProto portProto, NodeInst nodeInst) { PortInst pi = new PortInst(portProto, nodeInst); return pi; } /** * Method to return the NodeInst that this PortInst resides on. * @return the NodeInst that this PortInst resides on. */ public NodeInst getNodeInst() { return nodeInst; } /** * Method to return the PortProto that this PortInst is an instance of. * @return the PortProto that this PortInst is an instance of. */ public PortProto getPortProto() { return portProto; } /** * Method to get the index of this PortInst in NodeInst ports. * @return index of this PortInst in NodeInst ports. */ public final int getPortIndex() { return portProto.getPortIndex(); } /** * Returns true of there are Connections on this PortInst. * @return true if there are Connections on this PortInst. */ public boolean hasConnections() { Cell parent = nodeInst.getParent(); return parent != null && parent.getMemoization().hasConnections(nodeInst.getD(), portProto.getId()); } /** * Get iterator of all Connections * that connect to this PortInst * @return an iterator over associated Connections */ public Iterator<Connection> getConnections() { return nodeInst.getConnections(portProto.getId()); } /** * Get iterator of all Exports * that connect to this PortInst * @return an iterator over associated Exports */ public Iterator<Export> getExports() { List<Export> exports = new ArrayList<Export>(); // get exports on NodeInst for (Iterator<Export> it = nodeInst.getExports(); it.hasNext();) { Export e = it.next(); if (e.getOriginalPort() == this) { exports.add(e); } } return exports.iterator(); } /** ** Method to return the equivalent PortProto of this PortInst's PortProto. * This is typically used to find the PortProto in the schematic view. * @return the equivalent PortProto of this PortInst's PortProto, or null if not found. */ public PortProto getProtoEquivalent() { return portProto instanceof Export ? ((Export) portProto).getEquivalent() : portProto; } /** * Method to return the bounds of this PortInst. * The bounds are determined by getting the Poly and bounding it. * @return the bounds of this PortInst. */ public Rectangle2D getBounds() { return getPoly().getBounds2D(); } public EPoint getCenter() { return getPoly().getCenter(); } /** * Method to return the Poly that describes this PortInst. * @return the Poly that describes this PortInst. */ public Poly getPoly() { return nodeInst.getShapeOfPort(portProto); } /** * Method to add all displayable Variables on this PortInsts to an array of Poly objects. * @param rect a rectangle describing the bounds of the NodeInst on which the PortInsts reside. * @param polys an array of Poly objects that will be filled with the displayable Variables. * @param start the starting index in the array of Poly objects to fill with displayable Variables. * @param wnd window in which the Variables will be displayed. * @param multipleStrings true to break multiline text into multiple Polys. * @return the number of Polys that were added. */ public int addDisplayableVariables(Rectangle2D rect, Poly[] polys, int start, EditWindow0 wnd, boolean multipleStrings) { if (super.numDisplayableVariables(multipleStrings) == 0) { return 0; } Poly portPoly = getPoly(); int justAdded = super.addDisplayableVariables(portPoly.getBounds2D(), polys, start, wnd, multipleStrings); for (int i = 0; i < justAdded; i++) { polys[start + i].setPort(getPortProto()); } return justAdded; } /** * Method to describe this NodeInst as a string. * @param withQuotes to wrap description between quotes * @return a description of this NodeInst as a string. */ public String describe(boolean withQuotes) { String info = nodeInst.describe(false) + "." + portProto.getName(); return (withQuotes) ? "'" + info + "'" : info; } /** * Returns a printable version of this PortInst. * @return a printable version of this PortInst. */ public String toString() { return "port " + describe(true); } /** * This function is to compare PortInst elements. Initiative CrossLibCopy * @param obj Object to compare to * @param buffer To store comparison messages in case of failure * @return True if objects represent same PortInst */ public boolean compare(Object obj, StringBuffer buffer) { if (this == obj) { return (true); } // Better if compare classes? but it will crash with obj=null if (obj == null || getClass() != obj.getClass()) { return (false); } PortInst no = (PortInst) obj; Set<Connection> noCheckAgain = new HashSet<Connection>(); for (Iterator<Connection> it = getConnections(); it.hasNext();) { Connection c = it.next(); boolean found = false; for (Iterator<Connection> noIt = no.getConnections(); noIt.hasNext();) { Connection noC = noIt.next(); if (noCheckAgain.contains(noC)) { continue; } if (c.getLocation().equals(noC.getLocation())) { found = true; noCheckAgain.add(noC); break; } } // No correspoding NodeInst found if (!found) { if (buffer != null) { buffer.append("No corresponding port " + this + " found in " + no + " at the location " + c.getLocation() + " \n"); } return (false); } } // @TODO GVG Check this // Just compare connections?? or just poly for now? Poly poly = getPoly(); Poly noPoly = no.getPoly(); boolean check = poly.compare(noPoly, buffer); if (!check && buffer != null) { buffer.append("No same ports detected in " + portProto.getName() + " and " + no.getPortProto().getName() + "\n"); } return (check); } /** * Overrides ElectricObject.isLinked(). This is because a PortInst is a derived * database object, and is never explicitly linked or unlinked. It represents a NodeInst * and PortProto pair. So, this method really returns it's nodeinst's isLinked() * value. * @return true if the object is linked into the database, false if not. */ public boolean isLinked() { try { return nodeInst != null && nodeInst.isLinked() && nodeInst.getPortInst(getPortIndex()) == this; } catch (IndexOutOfBoundsException e) { return false; } } /** * Returns database to which this PortInst belongs. * Some objects are not in database, for example Geometrics in PaletteFrame. * Method returns null for non-database objects. * @return database to which this PortInst belongs. */ public EDatabase getDatabase() { return nodeInst.getDatabase(); } public Poly computeTextPoly(EditWindow0 wnd, Variable var, Name name) { Poly poly = null; if (var != null) { Rectangle2D bounds = getPoly().getBounds2D(); Poly[] polys = getPolyList(var, bounds.getCenterX(), bounds.getCenterY(), wnd, false); if (polys.length > 0) { poly = polys[0]; poly.transform(getNodeInst().rotateOut()); } } if (poly != null) { poly.setExactTextBounds(wnd, this); } return poly; } }