/*
* Created on 04-Mar-2004
* Author is Michael Camacho
*/
package pipe.views;
import pipe.constants.GUIConstants;
import pipe.controllers.PetriNetController;
import uk.ac.imperial.pipe.models.petrinet.Annotation;
import uk.ac.imperial.pipe.models.petrinet.AnnotationImpl;
import javax.swing.event.MouseInputAdapter;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
/**
* View representation of the annotation Petri net component
*/
@SuppressWarnings("serial")
public final class AnnotationView extends Note {
/**
* The number of points defined that can be dragged on the annotation to increase
* its size
*/
public static final int NO_DRAG_POINTS = 8;
/**
* Drag point locations on the annotation
*/
private final List<ResizePoint> dragPoints = new ArrayList<>(NO_DRAG_POINTS);
/**
* Affine transform for drawing purposes. This transform is applied
* to the rectange and can be used to rotate, stretch etc the annotation
*/
private AffineTransform prova = new AffineTransform();
/**
* Constructor
* @param annotation underlying annotation model
* @param controller Petri net controller for the Petri net the annotation belongs to
* @param parent parent container of this view
* @param handler how the annotation will handle mouse events
*/
public AnnotationView(Annotation annotation, PetriNetController controller, Container parent, MouseInputAdapter handler) {
super(annotation, controller, parent);
addChangeListener(annotation);
setDragPoints();
setMouseHandler(handler);
updateBounds();
}
/**
* Registers the handler to this view
* @param handler how the annotation will handle mouse events
*/
private void setMouseHandler(MouseInputAdapter handler) {
addMouseListener(handler);
addMouseMotionListener(handler);
noteText.addMouseListener(handler);
noteText.addMouseMotionListener(handler);
}
/**
* Update the (x,y) and width height boundary of this view
*
* Implemented because the canvas has no layout manager
*/
@Override
public void updateBounds() {
super.updateBounds();
// TOP-LEFT
dragPoints.get(0).setLocation(noteRect.getMinX(), noteRect.getMinY());
// TOP-MIDDLE
dragPoints.get(1).setLocation(noteRect.getCenterX(), noteRect.getMinY());
// TOP-RIGHT
dragPoints.get(2).setLocation(noteRect.getMaxX(), noteRect.getMinY());
// MIDDLE-RIGHT
dragPoints.get(3).setLocation(noteRect.getMaxX(), noteRect.getCenterY());
// BOTTOM-RIGHT
dragPoints.get(4).setLocation(noteRect.getMaxX(), noteRect.getMaxY());
// BOTTOM-MIDDLE
dragPoints.get(5).setLocation(noteRect.getCenterX(), noteRect.getMaxY());
// BOTTOM-LEFT
dragPoints.get(6).setLocation(noteRect.getMinX(), noteRect.getMaxY());
// MIDDLE-LEFT
dragPoints.get(7).setLocation(noteRect.getMinX(), noteRect.getCenterY());
}
/**
* @param x coordinate
* @param y coordinate
* @return true if (x, y) intersect annotation location
*/
@Override
public boolean contains(int x, int y) {
boolean pointContains = false;
for (ResizePoint dragPoint : dragPoints) {
pointContains |= dragPoint.contains(x - dragPoint.getX(), y - dragPoint.getY());
}
return super.contains(x, y) || pointContains;
}
/**
* Listens for changes to the annotation model
*
* @param annotation model to register changes to
*/
private void addChangeListener(Annotation annotation) {
annotation.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent propertyChangeEvent) {
String name = propertyChangeEvent.getPropertyName();
if (name.equals(AnnotationImpl.TEXT_CHANGE_MESSAGE)) {
String text = (String) propertyChangeEvent.getNewValue();
setText(text);
} else if (name.equals(Annotation.X_CHANGE_MESSAGE) || name.equals(Annotation.Y_CHANGE_MESSAGE)) {
updateBounds();
}
}
});
}
/**
* Creates drag points for all the corners and half way along
* each edge
*/
private void setDragPoints() {
dragPoints.add(new ResizePoint(ResizePoint.TOP | ResizePoint.LEFT));
dragPoints.add(new ResizePoint(ResizePoint.TOP));
dragPoints.add(new ResizePoint(ResizePoint.TOP | ResizePoint.RIGHT));
dragPoints.add(new ResizePoint(ResizePoint.RIGHT));
dragPoints.add(new ResizePoint(ResizePoint.BOTTOM | ResizePoint.RIGHT));
dragPoints.add(new ResizePoint(ResizePoint.BOTTOM));
dragPoints.add(new ResizePoint(ResizePoint.BOTTOM | ResizePoint.LEFT));
dragPoints.add(new ResizePoint(ResizePoint.LEFT));
for (ResizePoint dragPoint : dragPoints) {
ResizePointHandler handler = new ResizePointHandler(dragPoint);
dragPoint.addMouseListener(handler);
dragPoint.addMouseMotionListener(handler);
add(dragPoint);
}
}
/**
* Paints the annotation and its text using the graphics
* @param g graphics
*/
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
prova = g2.getTransform();
g2.setStroke(new BasicStroke(1.0f));
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);
if (isSelected() && !ignoreSelection) {
g2.setPaint(GUIConstants.SELECTION_FILL_COLOUR);
g2.fill(noteRect);
if (drawBorder) {
g2.setPaint(GUIConstants.SELECTION_LINE_COLOUR);
g2.draw(noteRect);
}
} else {
g2.setPaint(GUIConstants.ELEMENT_FILL_COLOUR);
/*
*/
boolean fillNote = true;
if (fillNote) {
g2.fill(noteRect);
}
if (drawBorder) {
g2.setPaint(GUIConstants.ELEMENT_LINE_COLOUR);
g2.draw(noteRect);
}
}
for (ResizePoint dragPoint : dragPoints) {
dragPoint.paintOnCanvas(g);
}
}
/**
* Noop
* @param container to add itself to
*/
@Override
public void addToContainer(Container container) {
//Noop
}
/**
* Noop
*/
@Override
public void componentSpecificDelete() {
//Noop
}
/**
* Deals with resizing of the annotation by handling mouse events
*/
private class ResizePointHandler extends javax.swing.event.MouseInputAdapter {
/**
* Point to perform actions to
*/
private final ResizePoint point;
/**
* Start point of resizing
*/
private Point start;
/**
* Constructor
* @param point the point to perform the resize to
*/
public ResizePointHandler(ResizePoint point) {
this.point = point;
}
/**
* When the mouse is pressed on the point repaint it and set the start location
* @param e mouse event
*/
@Override
public void mousePressed(MouseEvent e) {
point.isPressed = true;
point.repaint();
start = e.getPoint();
}
/**
* When the mouse is pressed on the point repaint it
* @param e mouse event
*/
@Override
public void mouseReleased(MouseEvent e) {
point.isPressed = false;
updateBounds();
point.repaint();
}
/**
* When the mouse is dragged, drag the point using the set start point when the mouse was pressed
* @param e mouse event
*/
@Override
public void mouseDragged(MouseEvent e) {
point.drag(e.getX() - start.x, e.getY() - start.y);
updateBounds();
point.repaint();
}
}
/**
* Resizable point for changing the size of the annotation
* These appear on the boarder of the annotation
*/
public class ResizePoint extends javax.swing.JComponent {
/**
* Top horizontal of the annotation box
*/
private static final int TOP = 1;
/**
* Bottom horizontal of the annotation box
*/
private static final int BOTTOM = 2;
/**
* Left vertical of the annotation box
*/
private static final int LEFT = 4;
/**
* Right vertical of the annotation box
*/
private static final int RIGHT = 8;
public final int typeMask;
/**
* Size of the point
*/
private static final int SIZE = 3;
/**
* Graphical representation of each point
*/
private Rectangle shape;
/**
* True if the point has been pressed
*/
private boolean isPressed = false;
/**
* Constructor
* @param type of point
*/
public ResizePoint(int type) {
setOpaque(false);
setBounds(-SIZE - 1, -SIZE - 1, 2 * SIZE + GUIConstants.ANNOTATION_SIZE_OFFSET + 1,
2 * SIZE + GUIConstants.ANNOTATION_SIZE_OFFSET + 1);
typeMask = type;
}
/**
* Set the x,y location of the point
* @param x coordinate
* @param y coordinate
*/
public void setLocation(double x, double y) {
super.setLocation((int) (x - SIZE), (int) (y - SIZE));
}
/**
* Drag the point by x, y
* @param x coordinate
* @param y coordinate
*/
private void drag(int x, int y) {
if ((typeMask & TOP) == TOP) {
adjustTop(y);
}
if ((typeMask & BOTTOM) == BOTTOM) {
adjustBottom(y);
}
if ((typeMask & LEFT) == LEFT) {
adjustLeft(x);
}
if ((typeMask & RIGHT) == RIGHT) {
adjustRight(x);
}
}
/**
* Paint the point on the canvas
* @param g graphics
*/
public void paintOnCanvas(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.setTransform(prova);
if (isSelected() && !AbstractPetriNetViewComponent.ignoreSelection) {
g2.translate(this.getLocation().x, this.getLocation().y);
shape = new Rectangle(0, 0, 2 * SIZE, 2 * SIZE);
g2.fill(shape);
g2.setStroke(new BasicStroke(1.0f));
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if (isPressed) {
g2.setPaint(GUIConstants.RESIZE_POINT_DOWN_COLOUR);
} else {
g2.setPaint(GUIConstants.ELEMENT_FILL_COLOUR);
}
g2.fill(shape);
g2.setPaint(GUIConstants.ELEMENT_LINE_COLOUR);
g2.draw(shape);
g2.setTransform(prova);
}
}
}
}