package com.jedics.graph.visual;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.util.LinkedList;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.border.Border;
import com.jedics.graph.Vertex;
import com.jedics.graph.visual.event.VertexChangeListener;
import com.jedics.graph.visual.event.VertexEvent;
/**
*
* This class represents a Vertex that is visible on the graph.
*
* @author Abhishek Shroff
*
*/
@SuppressWarnings("serial")
public class VertexComponent extends JComponent {
private static final int PADDING = 5;
private static final Border PADDED_BORDER = BorderFactory.createEmptyBorder(0, PADDING, 0, PADDING);
private static final int MIN_SIZE = 20;
private static final int MAX_DATA_SIZE = 100;
private static final int MAX_EAST_SIZE = 70;
private static final int DATA_HEIGHT = 25;
private static final int SOUTH_HEIGHT = 25;
boolean changing = false;
private LinkedList<VertexChangeListener> vertexChangeListeners;
/**
* Label to hold the data inside the Vertex
*/
private JLabel data;
/**
* Label to hold the data to the east. Meant for showing distances in algorithms.
*/
private JLabel east;
/**
* Label to hold the data to the south. Meant for showing parent in algorithms.
*/
private JLabel south;
/**
* Used to calculate perceived starting/ending point of Edges
*/
private Point center;
/**
* Color of the border. Can be changed during animation.
*/
private Color borderColor = Color.black;
private Vertex vertex;
/**
*
* Creates a new vertex with th given ID and Driver. Its initial data is set to its ID.
*
* @param id unique (unless cloned) ID of the vertex
* @param driver The driver controlling this vertex.
*/
public VertexComponent(Vertex v) {
this.vertex = v;
this.center = new Point();
vertexChangeListeners = new LinkedList<VertexChangeListener>();
setLayout(null);
data = new JLabel();
data.setBorder(PADDED_BORDER);
data.setBounds(5, 7, 20, 20);
data.setHorizontalAlignment(JTextField.CENTER);
data.setVerticalAlignment(JTextField.CENTER);
add(data);
east = new JLabel();
east.setBorder(PADDED_BORDER);
east.setHorizontalAlignment(SwingConstants.CENTER);
east.setVerticalAlignment(SwingConstants.CENTER);
add(east);
south = new JLabel();
south.setBorder(PADDED_BORDER);
south.setHorizontalAlignment(SwingConstants.CENTER);
south.setVerticalAlignment(SwingConstants.CENTER);
add(south);
changing = false;
setForeground(Color.black);
setData(getId() + "");
setLayout(null);
setFocusable(false);
setOpaque(true);
setBackground(Color.white);
}
public void paintComponent(Graphics _g) {
Graphics2D g = (Graphics2D)_g;
if(isOpaque()) {
g.setColor(getBackground());
g.fillRect(1, 1, getWidth()-2, getHeight()-2);
}
g.setColor(borderColor);
g.drawRect(0, 0, getWidth()-1, getHeight()-1);
if(!east.getText().equals("")) {
g.drawLine(east.getX()-1, 1, east.getX()-1, 1+east.getHeight());
}
if(!south.getText().equals("")) {
g.drawLine(1, south.getY()-1, getWidth(), south.getY()-1);
}
}
/**
* @see java.lang.Object#equals(Object)
*/
@Override
public boolean equals(Object o) {
if(!(o instanceof VertexComponent)) return false;
return getId() == ((VertexComponent)o).getId();
}
public void setData(String s) {
data.setText(s);
recalcSize();
}
public String getData() {
return data.getText();
}
public void setEastText(String s) {
east.setText(s);
recalcSize();
}
public String getEastText() {
return east.getText();
}
public void setSouthText(String s) {
south.setText(s);
recalcSize();
}
public String getSouthText() {
return south.getText();
}
public void setBorderColor(Color bc) {
borderColor = bc;
}
public Color getBorderColor() {
return borderColor;
}
public void setForeground(Color fg) {
data.setForeground(fg);
east.setForeground(fg);
south.setForeground(fg);
}
public Color getForeground() {
return data.getForeground();
}
public void resetDefaultColors() {
setBackground(Color.white);
setForeground(Color.black);
setBorderColor(Color.black);
}
public void setLocation(int x, int y) {
center.x = x + getWidth()/2;
center.y = y + getHeight()/2;
super.setLocation(x, y);
fireVertexLocationChanged();
}
void positionCentered(int x, int y) {
center.x = x;
center.y = y;
super.setLocation(x - getWidth() /2, y - getHeight()/2);
fireVertexLocationChanged();
}
public void setSize(int w, int h) {
super.setSize(w, h);
super.setLocation(center.x-w/2, center.y-h/2);
}
public void recalcSize() {
int w1 = Math.min(MAX_DATA_SIZE, Math.max(MIN_SIZE, data.getPreferredSize().width));
int w2 = 0;
int h = 0;
data.setLocation(1, 1);
if(!east.getText().equals("")) {
w2 = Math.min(MAX_EAST_SIZE, Math.max(MIN_SIZE, east.getPreferredSize().width));
east.setSize(w2++, DATA_HEIGHT);
}
if(!south.getText().equals("")) {
south.setLocation(1, DATA_HEIGHT + 2);
w1 = (int)Math.max(w1, Math.min(south.getPreferredSize().getWidth() - w2, MAX_DATA_SIZE + MAX_EAST_SIZE));
if(w1 > MAX_DATA_SIZE && w2 != 0) {
w2 += w1 - MAX_DATA_SIZE;
w1 = MAX_DATA_SIZE;
}
h = SOUTH_HEIGHT+1;
south.setSize(w1+w2, SOUTH_HEIGHT);
}
data.setSize(w1, DATA_HEIGHT);
east.setLocation(w1+2, 1);
setSize(w1+w2+2, DATA_HEIGHT+h+2);
repaint();
}
public void addVertexChangeListener(VertexChangeListener listener) {
vertexChangeListeners.add(listener);
}
public void fireVertexSizeChanged() {
for(VertexChangeListener l : vertexChangeListeners) {
l.vertexSizeChanged(new VertexEvent(this, false));
}
}
public void fireVertexLocationChanged() {
for(VertexChangeListener l : vertexChangeListeners) {
l.vertexLocationChanged(new VertexEvent(this, changing));
}
}
public Point getCenter() {
return center;
}
public int getId() {
return vertex.getId();
}
}