/* ==============================================
* Simtools : The tools library used in JSynoptic
* ==============================================
*
* Project Info: http://jsynoptic.sourceforge.net/index.html
*
* This library is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* (C) Copyright 1999-2003, by :
* Corporate:
* Astrium SAS
* EADS CRC
* Individual:
* Claude Cazenave
* Nicolas Brodu
*
*
* $Id: Gate.java,v 1.5 2009/01/15 12:27:04 ogor Exp $
*
* Changes
* -------
* 08-Sep-2008 : Initial public release (RO);
*
*/
package simtools.diagram.gate;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Point;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import simtools.shapes.TipShape;
/**
* A gate is an anchor gathered by a {@link GatedComponent}.
* A gate can be connected to several {@link Connection}.
*
* A gate is defined by:
* <ul>
* <li> An string ID
* <li>A position inside the component
* <li> A color
* </ul>
* @author zxpletran007
*/
public class Gate implements Serializable, Cloneable{
private static final long serialVersionUID = -1950675004653900776L;
protected static final int GATE_SIZE = 5;
protected static final int HIGHLIGHTED_GATE_SIZE = 7;
public static final Color DEFAULT_GATE_COLOR = Color.BLUE;
public static final int NORTH = 0;
public static final int EAST = 1;
public static final int SOUTH = 2;
public static final int WEST = 3;
/**
* When the mouse and the gate position are spaced out of a distance lower than this value, it is possible to
* select the gate.
*
*/
protected final static int MAX_DISTANCE_FOR_HANGING = 16;
/**
* The component the gate belongs to
*/
protected GatedComponent component;
/**
* The connection attached to this gate
*/
protected List connections;
/**
* Gate id
*/
protected String id;
/**
* Current gate color
*/
protected Color color;
/**
* The component side in witch the gate is positioned
*/
protected int side;
protected transient TipShape tipShape = null;
/**
* Create a gate
* @param component - The component the gate is attached to
* @param side - The component side in witch the gate is positioned
* @param id - Gate id
*/
public Gate(GatedComponent component, int side, String id){
this.component = component;
this.connections = new ArrayList();
this.side = side;
this.id = id;
this.color = DEFAULT_GATE_COLOR;
}
/**
* Create a gate without Id
* @param component - The component the gate is attached to
* @param side - The component side in witch the gate is positioned
*/
public Gate(GatedComponent component, int side){
this(component, side, null);
}
/**
* Clone the gate for the new gate owner
* @param owner
* @return - the cloned gate
*/
public Gate cloneGate(GatedComponent owner){
Gate res = null;
try{
res = (Gate)super.clone();
res.component = owner;
res.connections = new ArrayList(); // no connection for the cloned gate
res.id = id;
res.color = color;
res.side = side;
}
catch(CloneNotSupportedException cnse){
}
return res;
}
/**
* @return the component the gate is attached to
*/
public GatedComponent getOwner(){
return component;
}
/**
* Typically, the gate owner should provide the gate position regarding its current dimension.
* Subclass shall specify the way the get this position
* @return the gate anchor
*/
public Point getAnchor() {
return component.getGateAnchor(this);
}
/**
* return true if the given point is close enough from the gate to be hanged
* @param p
* @return
*/
public boolean canBeHanged(Point p){
Point anchor = getAnchor();
return (anchor.x - p.x)*(anchor.x - p.x) + (anchor.y - p.y)*(anchor.y - p.y) < MAX_DISTANCE_FOR_HANGING*MAX_DISTANCE_FOR_HANGING;
}
/**
* Checks if this gate can be connected with another specified gate.
* Overload this class for specific needs
* @param gate - The candidate to be connected with this gate
* @return true if the gate can be connected to the given gate
*
*/
public boolean allowConnection(Gate gate){
boolean res = true;
if (gate != null){
res = !gate.equals(this) && !gate.getOwner().equals(this.getOwner());
}
return res;
}
/**
* Draw the gate
* @param g2
*/
public void drawGate(Graphics2D g2){
Color oldColor = g2.getColor();
Point p = getAnchor();
// Draw Gate anchor point
int x= p.x - GATE_SIZE/2;
int y= p.y - GATE_SIZE/2;
int w = GATE_SIZE;
int h = GATE_SIZE;
g2.setColor(color);
g2.fillRect(x, y, w, h);
g2.setColor(Color.WHITE);
g2.drawRect(x, y, w, h);
// restore color
g2.setColor(oldColor);
}
/**
* Draw the gate in highlighted status.
* The gate can be displayed differently whether or not it can be connected.
* @param g2
* @param canBeConnected
*/
public void drawGateInformation(Graphics2D g2, boolean canBeConnected) {
Color oldColor = g2.getColor();
Point p = getAnchor();
Color color = canBeConnected? Color.GREEN : Color.RED;
// Draw Gate anchor point
int x= p.x - HIGHLIGHTED_GATE_SIZE/2;
int y= p.y - HIGHLIGHTED_GATE_SIZE/2;
int w = HIGHLIGHTED_GATE_SIZE;
int h = HIGHLIGHTED_GATE_SIZE;
g2.setColor(color);
g2.fillRect(x, y, w, h);
g2.setColor(Color.WHITE);
g2.drawRect(x, y, w, h);
// Draw Gate information
if (id != null && !id.equals("")){
if (tipShape == null){
tipShape = new TipShape(id, x, y);
} else {
tipShape.setAnchor(x + HIGHLIGHTED_GATE_SIZE, y);
}
tipShape.draw(g2);
}
// restore color
g2.setColor(oldColor);
}
/**
* The gate is connected to the given connection
* The component is notified from this new connection.
* @param connection
*/
public void connectTo(Connection connection){
if (!connections.contains(connection)){
connections.add(connection);
}
// The component is notified from this new connection.
component.connectionAddedAt(this, connection);
}
/**
* The gate is disconnected to the given connection
* The component is notified
* @param connection
*/
public void disconnectFrom(Connection connection){
connections.remove(connection);
// The component is notified from this new connection.
component.connectionRemovedAt(this, connection);
}
/**
* @return all gate connections
*/
public List getConnections(){
return connections;
}
/**
* @return gate ID
*/
public String getGateId() {
return id;
}
/**
* Set gate Id
* @param label
*/
public void setGateId(String label) {
this.id = label;
}
/**
* Set gate color
* @param color
*/
public void setColor(Color color) {
this.color = color;
}
/**
* @return gate color
*/
public Color getColor() {
return color;
}
/**
* @return- the component side on witch the gate is positioned
*/
public int getSide() {
return side;
}
/**
* Return the squared distance between the point and this gate
* @param p - the point
* @return Return the distance between the point and this gate
*/
public int getSquaredDistance(Point p){
Point gateCenter = getAnchor();
return (gateCenter.x - p.x)*(gateCenter.x - p.x) + (gateCenter.y - p.y)*(gateCenter.y - p.y);
}
}