//Copyright (c)2005 Holobloc Inc.
//Contributed to the OOONEIDA FBench project under the Common Public License.
//Copyright (c) 2007 University of Auckland
//Contributed to the FBench extension of the OOONEIDA Workbench project under the Common Public License
package fbench.graph;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JLabel;
import fbench.IconFactory;
import fbench.graph.popup.ContextMenu;
import fbench.graph.popup.FBNetworkDialog;
import org.w3c.dom.Element;
/**
* A GraphEdge encsapsulating an IEC 61499 <TT>Connection</TT> element.
*
* @author JHC, JP
*
* @version 20070301/JP - Linked with edit/remove dialog
* @version 20070130/JP - Added MouseListener, MouseMotionListener for graphical interaction
* @version 20051010/JHC - Changed path to polyline.
* @version 20050818/JHC
*/
public class Connection extends GraphEdge {
private Point mousePoint = new Point();
private float scaleFactor = Float.parseFloat(
""+((getFontMetrics(getFont()).getHeight() + 4.0) / 100.0));
private int selectedSegment = 0;
int value = 0;
public Connection() {
super();
setLayout(new BorderLayout());
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent evt) {
processMousePressed(evt);
}
public void mouseReleased(MouseEvent evt) {
processMouseReleased(evt);
}
public void mouseClicked(MouseEvent evt) {
processMouseClicked(evt);
}
});
addMouseMotionListener(new MouseMotionAdapter(){
public void mouseDragged(MouseEvent evt){
processMouseDragged(evt);
}
});
}
private void processMousePressed(MouseEvent evt){
if(getDestPoint() != null && getSourcePoint() != null){
if(getParent().getMousePosition() != null)
mousePoint = getParent().getMousePosition();
int x = evt.getX()+getX();
int y = mousePoint.y - getSourcePoint().y;
if(x < getSourcePoint().x+ getScaledAtt("dx1")+5 && x > getSourcePoint().x+ getScaledAtt("dx1")-5){
selectedSegment = 1;
value = getScaledAtt("dx1");
}
else if(x < getDestPoint().x - getScaledAtt("dx2")+5 && x > getDestPoint().x - getScaledAtt("dx2")-5){
selectedSegment = 2;
value = getScaledAtt("dx2");
}
else if(y < getScaledAtt("dy")+5 && y > getScaledAtt("dy")-5){
selectedSegment = 3;
value = getScaledAtt("dy");
}
else
selectedSegment = 0;
} else{
selectedSegment = 0;
}
}
private void processMouseClicked(MouseEvent evt){
if(isInFBench()){
if(evt.getButton() == MouseEvent.BUTTON1 && evt.getClickCount() == 2){
FBNetworkDialog fbNetworkDialog = new FBNetworkDialog(getElement(), evt);
fbNetworkDialog.create("Edit Connection");
}
else if(evt.getButton() == MouseEvent.BUTTON3){
ContextMenu contextMenu = new ContextMenu(getElement(), evt);
contextMenu.create(getElement().getNodeName());
}
}
}
private void processMouseDragged(MouseEvent evt){
if(getParent().getMousePosition() != null){
if(selectedSegment == 1){
int xTransition = getParent().getMousePosition().x - mousePoint.x;
value = value + xTransition;
if(value >0)
getElement().setAttribute("dx1", ""+value/scaleFactor);
}
else if(selectedSegment == 2){
int xTransition = getParent().getMousePosition().x - mousePoint.x;
value = value - xTransition;
if(value >0)
getElement().setAttribute("dx2", ""+value/scaleFactor);
}
else if(selectedSegment == 3){
int yTransition = getParent().getMousePosition().y - mousePoint.y;
value = value + yTransition;
getElement().setAttribute("dy", ""+value/scaleFactor);
}
mousePoint = getParent().getMousePosition();
setBounds(getPreferredBounds());
repaint();
}
}
private void processMouseReleased(MouseEvent evt){
selectedSegment = 0;
}
public Component getSource() {
source = super.getSource();
if (source != null)
return source;
if (getComponentCount() == 0)
addLabel(true);
return null;
}
public Component getDest() {
dest = super.getDest();
if (dest != null)
return dest;
if (getComponentCount() == 0)
addLabel(false);
return null;
}
public Component getEndPtComponent(boolean findSource) {
String s = getElement().getAttribute(
findSource ? "Source" : "Destination");
int n = s.indexOf('.');
if (n <= 0)
return null;
if (n >= (s.length() - 1))
return null;
GraphNode fb = getNodeNamed(s.substring(0, n));
if (!(fb instanceof FB))
return null;
return fb.getComponentNamed(s.substring(n + 1));
}
/**
* Returns the middle of the right edge of the source element, or <TT>null
* </TT> if the source does not exist.
*/
public Point getSourcePoint() {
Rectangle r = GraphEdge.getBounds(getSource());
if (r == null)
return null;
return new Point(r.x + r.width - 1, r.y + r.height / 2);
}
/**
* Returns the middle of the left edge of the destination element, or <TT>
* null</TT> if the destination does not exist.
*/
public Point getDestPoint() {
Rectangle r = GraphEdge.getBounds(getDest());
if (r == null)
return null;
return new Point(r.x, r.y + r.height / 2);
}
/** Updates the path used to draw the element. */
public void updatePath() {
Point sp = getSourcePoint();
Point dp = getDestPoint();
if ((sp == null) || (dp == null))
return;
int dx2 = getScaledAtt("dx2");
int dy = getScaledAtt("dy");
if (dx2 > 0) {
if (pathx.length != 6) {
pathx = new int[6];
pathy = new int[6];
}
} else if (pathx.length != 4) {
pathx = new int[4];
pathy = new int[4];
}
pathx[0] = sp.x;
pathy[0] = sp.y;
pathx[1] = sp.x + getScaledAtt("dx1");
pathy[1] = sp.y;
if (dx2 > 0) {
pathx[2] = pathx[1];
pathy[2] = sp.y + dy;
pathx[3] = dp.x - dx2;
pathy[3] = pathy[2];
}
pathx[pathx.length - 2] = pathx[pathx.length - 3];
pathy[pathx.length - 2] = dp.y;
pathx[pathx.length - 1] = dp.x;
pathy[pathx.length - 1] = dp.y;
}
/**
* If this component contains a source or destination label, returns an
* appropriate boundary for drawing it plus a connection line; otherwise,
* returns the bounds of the drawn path.
*/
public Rectangle getPreferredBounds() {
Point sp = getSourcePoint();
Point dp = getDestPoint();
if (getComponentCount() == 0)
return super.getPreferredBounds();
Dimension d = getPreferredSize();
Rectangle r = new Rectangle(0, 0, d.width, d.height);
if (sp != null) {
r.x = sp.x;
r.y = sp.y;
} else if (dp != null) {
r.x = dp.x - d.width;
r.y = dp.y;
}
r.y -= d.height / 2;
return r;
}
Color selectedColor = new Color(119, 190, 255);
public void paintComponent(Graphics g) {
if (getComponentCount() == 0)
super.paintComponent(g);
else {
Color oldcolor = g.getColor();
g.setColor(isSelected() ? selectedColor : Color.white);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(oldcolor);
}
}
public boolean contains(int x, int y) {
return (getComponentCount() == 0) ? super.contains(x, y)
: getComponent(0).contains(x, y);
}
/** Returns <TT>true</TT> if this is an event connection. */
public boolean isEventConnection() {
Element el = model.getElement();
if (el == null)
return false;
el = (Element) el.getParentNode();
return el.getTagName().equals("EventConnections");
}
/** The color for deselected elements of this type. */
public Color getDeselectedColor() {
return isEventConnection() ? Color.green : Color.blue;
}
public void initComponents() {
setToolTipText(toString());
}
public String toString() {
return getElement().getAttribute("Source") + " TO "
+ getElement().getAttribute("Destination");
}
public String getAttrSource() {
return getElement().getAttribute("Source");
}
public String getAttrDesination() {
return getElement().getAttribute("Destination");
}
/**
* Add a label at the given location.
*
* @param loc <TT>true</TT> for an input value, <TT>false</TT> for an
* output value.
*/
public void addLabel(boolean loc) {
((ViewModel) getParent()).setLayer(this, ViewModel.IO_LAYER.intValue());
setOpaque(true);
JLabel lbl = new JLabel(IconFactory.getIcon("hline15"));
lbl.setText(getElement().getAttribute(loc ? "Source" : "Destination"));
lbl.setHorizontalTextPosition(loc ? JLabel.LEFT : JLabel.RIGHT);
lbl.setBorder(GraphElement.emborder);
lbl.setBackground(Color.white);
lbl.setFont(getFont());
add(lbl, BorderLayout.CENTER);
}
}