package pipe.views;
import org.jfree.util.ShapeUtilities;
import pipe.constants.GUIConstants;
import pipe.controllers.PetriNetController;
import uk.ac.imperial.pipe.models.petrinet.Transition;
import javax.swing.event.MouseInputAdapter;
import java.awt.*;
import java.awt.event.MouseListener;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
/**
* View representation of a transition component
*/
@SuppressWarnings("serial")
public class TransitionView extends ConnectableView<Transition> {
/**
* True if the transition view has been selected
*/
public boolean highlighted;
public Shape unrotated;
/**
* Constructor
*
* @param model underlying transition model
* @param controller Petri net controller of the Petri net the transition is housed in
* @param parent parent of the view
* @param transitionHandler mouse listener actions for the transition when in edit mode
* @param animationHandler mouse listener actions for the transition when in animation mode
*/
public TransitionView(Transition model, PetriNetController controller, Container parent,
MouseInputAdapter transitionHandler, MouseListener animationHandler) {
super(model.getId(), model, controller, controller.getTransitionController(model), parent,
new Rectangle2D.Double(-model.getWidth()/2, -model.getHeight()/2, model.getWidth(), model.getHeight()));
unrotated = new Rectangle2D.Double(-model.getWidth()/2, -model.getHeight()/2, model.getWidth(), model.getHeight());
setChangeListener();
highlighted = false;
rotate(model.getAngle());
//TODO: DEBUG WHY CANT CALL THIS IN CONSTRUCTOR
// changeToolTipText();
setMouseListener(transitionHandler, animationHandler);
}
/**
* Listen for property changes of the underlying mode and trigger a repaint
*/
private void setChangeListener() {
model.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent propertyChangeEvent) {
String name = propertyChangeEvent.getPropertyName();
switch (name) {
case Transition.PRIORITY_CHANGE_MESSAGE:
case Transition.RATE_CHANGE_MESSAGE:
repaint();
break;
case Transition.ANGLE_CHANGE_MESSAGE:
int angle = (int) propertyChangeEvent.getNewValue();
rotate(angle);
case Transition.TIMED_CHANGE_MESSAGE:
case Transition.INFINITE_SEVER_CHANGE_MESSAGE:
repaint();
break;
case Transition.ENABLED_CHANGE_MESSAGE:
case Transition.DISABLED_CHANGE_MESSAGE:
repaint();
break;
default:
break;
}
}
});
}
/**
* Rotate the transition
*
* Currently doesn't work
* @param angle to rotate
*/
public final void rotate(int angle) {
shape = ShapeUtilities.rotateShape(unrotated, Math.toRadians(angle), 0,0);
Rectangle bounds = shape.getBounds();
Rectangle newBounds = new Rectangle((int)(model.getCentre().getX() + bounds.getX()), (int)(model.getCentre().getY() + bounds.getY()), (int) bounds.getWidth() + getComponentDrawOffset(), (int)bounds.getHeight() + getComponentDrawOffset()) ;
setBounds(newBounds);
}
/**
* Register the mouse listeners to this view
*
* @param transitionHandler mouse listener actions for the transition when in edit mode
* @param animationHandler mouse listener actions for the transition when in animation mode
*/
private void setMouseListener(MouseInputAdapter transitionHandler, MouseListener animationHandler) {
addMouseListener(transitionHandler);
addMouseMotionListener(transitionHandler);
addMouseWheelListener(transitionHandler);
addMouseListener(animationHandler);
}
/**
* Paints the transition, if the model is enabled it will paint the transition in red
* @param g graphics
*/
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Rectangle rect = shape.getBounds();
g2.translate(rect.getWidth()/2, rect.getHeight()/2);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if (isSelected() && !ignoreSelection) {
g2.setColor(GUIConstants.SELECTION_FILL_COLOUR);
} else {
g2.setColor(GUIConstants.ELEMENT_FILL_COLOUR);
}
if (model.isTimed()) {
if (model.isInfiniteServer()) {
for (int i = 2; i >= 1; i--) {
g2.translate(2 * i, -2 * i);
g2.fill(shape);
Paint pen = g2.getPaint();
if (highlightView()) {
g2.setPaint(GUIConstants.ENABLED_TRANSITION_COLOUR);
} else if (isSelected() && !ignoreSelection) {
g2.setPaint(GUIConstants.SELECTION_LINE_COLOUR);
} else {
g2.setPaint(GUIConstants.ELEMENT_LINE_COLOUR);
}
g2.draw(shape);
g2.setPaint(pen);
g2.translate(-2 * i, 2 * i);
}
}
g2.fill(shape);
}
if (highlightView()) {
g2.setPaint(GUIConstants.ENABLED_TRANSITION_COLOUR);
} else if (isSelected() && !ignoreSelection) {
g2.setPaint(GUIConstants.SELECTION_LINE_COLOUR);
} else {
g2.setPaint(GUIConstants.ELEMENT_LINE_COLOUR);
}
g2.draw(shape);
if (!model.isTimed()) {
if (model.isInfiniteServer()) {
for (int i = 2; i >= 1; i--) {
g2.translate(2 * i, -2 * i);
Paint pen = g2.getPaint();
g2.setPaint(GUIConstants.ELEMENT_FILL_COLOUR);
g2.fill(shape);
g2.setPaint(pen);
g2.draw(shape);
g2.translate(-2 * i, 2 * i);
}
}
g2.draw(shape);
g2.fill(shape);
}
// changeToolTipText();
}
/**
* @return true if in animate mode and the model is enabled
*/
private boolean highlightView() {
return model.isEnabled() && petriNetController.isInAnimationMode();
}
/**
* Adds the name label to the container
* @param container to add itself to
*/
@Override
public void addToContainer(Container container) {
addLabelToContainer(container);
}
}