package com.mxgraph.swing.handler;
import com.intellij.icons.AllIcons;
import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.swing.util.mxMouseAdapter;
import com.mxgraph.util.*;
import com.mxgraph.util.mxEventSource.mxIEventListener;
import com.mxgraph.view.mxCellState;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
/**
* Basic example of implementing a handler for rotation. This can be used as follows:
* <p/>
* new mxRotationHandler(graphComponent)
* <p/>
* Note that the Java core does actually not support rotation for the selection handles,
* perimeter points etc. Feel free to contribute a fix!
*/
public class mxRotationHandler extends mxMouseAdapter {
/**
*
*/
private static double PI4 = Math.PI / 4;
/**
* Reference to the enclosing graph component.
*/
protected mxGraphComponent graphComponent;
/**
* Specifies if this handler is enabled. Default is true.
*/
protected boolean enabled = true;
/**
*
*/
protected JComponent handle;
/**
*
*/
protected mxCellState currentState;
/**
*
*/
protected double initialAngle;
/**
*
*/
protected double currentAngle;
/**
*
*/
protected Point first;
/**
* Constructs a new rotation handler.
*/
public mxRotationHandler(mxGraphComponent graphComponent) {
this.graphComponent = graphComponent;
graphComponent.addMouseListener(this);
handle = createHandle();
// Installs the paint handler
graphComponent.addListener(mxEvent.AFTER_PAINT, new mxIEventListener() {
public void invoke(Object sender, mxEventObject evt) {
Graphics g = (Graphics)evt.getProperty("g");
paint(g);
}
});
// Listens to all mouse events on the rendering control
graphComponent.getGraphControl().addMouseListener(this);
graphComponent.getGraphControl().addMouseMotionListener(this);
// Needs to catch events because these are consumed
handle.addMouseListener(this);
handle.addMouseMotionListener(this);
}
/**
*
*/
public mxGraphComponent getGraphComponent() {
return graphComponent;
}
/**
*
*/
public boolean isEnabled() {
return enabled;
}
/**
*
*/
public void setEnabled(boolean value) {
enabled = value;
}
/**
*
*/
protected JComponent createHandle() {
Icon refresh = AllIcons.Actions.Refresh;
JLabel label = new JLabel(refresh);
label.setSize(refresh.getIconWidth(), refresh.getIconHeight());
label.setOpaque(false);
return label;
}
/**
*
*/
public boolean isStateHandled(mxCellState state) {
return graphComponent.getGraph().getModel().isVertex(state.getCell());
}
/**
*
*/
public void mousePressed(MouseEvent e) {
if (currentState != null && handle.getParent() != null && e.getSource() == handle /* mouse hits handle */) {
start(e);
e.consume();
}
}
/**
*
*/
public void start(MouseEvent e) {
initialAngle = mxUtils.getDouble(currentState.getStyle(), mxConstants.STYLE_ROTATION) * mxConstants.RAD_PER_DEG;
currentAngle = initialAngle;
first = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(), graphComponent.getGraphControl());
if (!graphComponent.getGraph().isCellSelected(currentState.getCell())) {
graphComponent.selectCellForEvent(currentState.getCell(), e);
}
}
/**
*
*/
public void mouseMoved(MouseEvent e) {
if (graphComponent.isEnabled() && isEnabled()) {
if (handle.getParent() != null && e.getSource() == handle /* mouse hits handle */) {
graphComponent.getGraphControl().setCursor(new Cursor(Cursor.HAND_CURSOR));
e.consume();
}
else if (currentState == null || !currentState.getRectangle().contains(e.getPoint())) {
mxCellState eventState = graphComponent.getGraph().getView().getState(graphComponent.getCellAt(e.getX(), e.getY(), false));
mxCellState state = null;
if (eventState != null && isStateHandled(eventState)) {
state = eventState;
}
if (currentState != state) {
currentState = state;
if (currentState == null && handle.getParent() != null) {
handle.setVisible(false);
handle.getParent().remove(handle);
}
else if (currentState != null) {
if (handle.getParent() == null) {
// Adds component for rendering the handles (preview is separate)
graphComponent.getGraphControl().add(handle, 0);
handle.setVisible(true);
}
handle.setLocation((int)(currentState.getX() + currentState.getWidth() - handle.getWidth() - 4),
(int)(currentState.getY() + currentState.getHeight() - handle.getWidth() - 4));
}
}
}
}
}
/**
*
*/
public void mouseDragged(MouseEvent e) {
if (graphComponent.isEnabled() && isEnabled() && !e.isConsumed() && first != null) {
mxRectangle dirty = mxUtils.getBoundingBox(currentState, currentAngle * mxConstants.DEG_PER_RAD);
Point pt = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(), graphComponent.getGraphControl());
double cx = currentState.getCenterX();
double cy = currentState.getCenterY();
double dx = pt.getX() - cx;
double dy = pt.getY() - cy;
double c = Math.sqrt(dx * dx + dy * dy);
currentAngle = ((pt.getX() > cx) ? -1 : 1) * Math.acos(dy / c) + PI4 + initialAngle;
dirty.add(mxUtils.getBoundingBox(currentState, currentAngle * mxConstants.DEG_PER_RAD));
dirty.grow(1);
// TODO: Compute dirty rectangle and repaint
graphComponent.getGraphControl().repaint(dirty.getRectangle());
e.consume();
}
else if (handle.getParent() != null) {
handle.getParent().remove(handle);
}
}
/**
*
*/
public void mouseReleased(MouseEvent e) {
if (graphComponent.isEnabled() && isEnabled() && !e.isConsumed() && first != null) {
double deg = 0;
Object cell = null;
if (currentState != null) {
cell = currentState.getCell();
/*deg = mxUtils.getDouble(currentState.getStyle(),
mxConstants.STYLE_ROTATION);*/
}
deg += currentAngle * mxConstants.DEG_PER_RAD;
boolean willExecute = cell != null && first != null;
// TODO: Call reset before execute in all handlers that
// offer an execute method
reset();
if (graphComponent.isEnabled() && isEnabled() && !e.isConsumed() && willExecute) {
graphComponent.getGraph().setCellStyles(mxConstants.STYLE_ROTATION, String.valueOf(deg), new Object[]{cell});
graphComponent.getGraphControl().repaint();
e.consume();
}
}
currentState = null;
}
/**
*
*/
public void reset() {
if (handle.getParent() != null) {
handle.getParent().remove(handle);
}
mxRectangle dirty = null;
if (currentState != null && first != null) {
dirty = mxUtils.getBoundingBox(currentState, currentAngle * mxConstants.DEG_PER_RAD);
dirty.grow(1);
}
currentState = null;
currentAngle = 0;
first = null;
if (dirty != null) {
graphComponent.getGraphControl().repaint(dirty.getRectangle());
}
}
/**
*
*/
public void paint(Graphics g) {
if (currentState != null && first != null) {
Rectangle rect = currentState.getRectangle();
double deg = currentAngle * mxConstants.DEG_PER_RAD;
if (deg != 0) {
((Graphics2D)g).rotate(Math.toRadians(deg), currentState.getCenterX(), currentState.getCenterY());
}
mxUtils.setAntiAlias((Graphics2D)g, true, false);
g.drawRect(rect.x, rect.y, rect.width, rect.height);
}
}
}