
org.yaoqiang.graph.handler.GraphHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of yaoqiang-bpmn-editor Show documentation
Show all versions of yaoqiang-bpmn-editor Show documentation
an Open Source BPMN 2.0 Modeler
package org.yaoqiang.graph.handler;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.TransferHandler;
import org.yaoqiang.graph.model.GraphModel;
import org.yaoqiang.graph.swing.GraphComponent;
import org.yaoqiang.graph.util.Constants;
import org.yaoqiang.graph.view.Graph;
import com.mxgraph.model.mxCell;
import com.mxgraph.model.mxGeometry;
import com.mxgraph.model.mxIGraphModel;
import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.swing.mxGraphComponent.mxGraphControl;
import com.mxgraph.swing.handler.mxCellMarker;
import com.mxgraph.swing.handler.mxGraphHandler;
import com.mxgraph.swing.handler.mxGraphTransferHandler;
import com.mxgraph.swing.util.mxSwingConstants;
import com.mxgraph.util.mxPoint;
import com.mxgraph.util.mxUtils;
import com.mxgraph.view.mxCellState;
import com.mxgraph.view.mxGraph;
/**
* GraphHandler
*
* @author Shi Yaoqiang([email protected])
*/
public class GraphHandler extends mxGraphHandler {
public GraphHandler(mxGraphComponent graphComponent) {
super(graphComponent);
}
public GraphComponent getGraphComponent() {
return (GraphComponent) graphComponent;
}
protected mxCellMarker createMarker() {
mxCellMarker marker = new mxCellMarker(graphComponent, Color.BLUE) {
/**
*
*/
private static final long serialVersionUID = -8451338653189373347L;
/**
*
*/
public boolean isEnabled() {
return graphComponent.getGraph().isDropEnabled();
}
/**
*
*/
public Object getCell(MouseEvent e) {
mxIGraphModel model = graphComponent.getGraph().getModel();
TransferHandler th = graphComponent.getTransferHandler();
boolean isLocal = th instanceof mxGraphTransferHandler && ((mxGraphTransferHandler) th).isLocalDrag();
Graph graph = getGraphComponent().getGraph();
Object cell = super.getCell(e);
Object[] cells = (isLocal) ? graph.getSelectionCells() : dragCells;
cell = graph.getDropTarget(cells, e.getPoint(), cell);
// Checks if parent is dropped into child
Object parent = cell;
while (parent != null) {
if (mxUtils.contains(cells, parent)) {
return null;
}
parent = model.getParent(parent);
}
boolean clone = graphComponent.isCloneEvent(e) && cloneEnabled;
if (isLocal && cell != null && cells.length > 0 && !clone && graph.getModel().getParent(cells[0]) == cell) {
cell = null;
}
// ==============start==============
if (graph.getSelectionCells().length > 0) {
Object selectedCell = graph.getSelectionCells()[0];
if (graph.getModel().isBoundaryEvent(selectedCell)) {
cell = graph.getModel().getParent(selectedCell);
}
}
// ==============end================
return cell;
}
};
// Swimlane content area will not be transparent drop targets
marker.setSwimlaneContentEnabled(true);
return marker;
}
protected Cursor getCursor(MouseEvent e) {
Cursor cursor = null;
if (isMoveEnabled()) {
Object cell = graphComponent.getCellAt(e.getX(), e.getY(), false);
if (cell != null) {
if (graphComponent.isFoldingEnabled() && graphComponent.hitFoldingIcon(cell, e.getX(), e.getY())) {
cursor = FOLD_CURSOR;
} else if (graphComponent.getGraph().isCellMovable(cell)) {
// ==============start==============
if (graphComponent.getGraph().getModel().isEdge(cell)) {
cursor = new Cursor(Cursor.HAND_CURSOR);
} else {
cursor = MOVE_CURSOR;
}
// ==============end================
}
}
}
return cursor;
}
public void mousePressed(MouseEvent e) {
if (graphComponent.isEnabled() && isEnabled() && !e.isConsumed() && !graphComponent.isForceMarqueeEvent(e)) {
cell = graphComponent.getCellAt(e.getX(), e.getY(), false);
// ==============start==============
Graph graph = getGraphComponent().getGraph();
GraphModel model = graph.getModel();
if (model.isChoreographyTask(cell) || model.isChoreographySubprocess(cell) || model.isChoreographyParticipant(cell)) {
cell = model.getParent(cell);
}
// ==============end================
initialCell = cell;
if (cell != null) {
if (isSelectEnabled() && !graphComponent.getGraph().isCellSelected(cell)) {
graphComponent.selectCellForEvent(cell, e);
cell = null;
}
// Starts move if the cell under the mouse is movable and/or any
// cells of the selection are movable
if (isMoveEnabled() && !e.isPopupTrigger()) {
start(e);
e.consume();
}
} else if (e.isPopupTrigger()) {
graphComponent.getGraph().clearSelection();
}
}
}
public void mouseDragged(MouseEvent e) {
// LATER: Check scrollborder, use scroll-increments, do not
// scroll when over ruler dragging from library
graphComponent.getGraphControl().scrollRectToVisible(new Rectangle(e.getPoint()));
if (!e.isConsumed()) {
gridEnabledEvent = graphComponent.isGridEnabledEvent(e);
constrainedEvent = graphComponent.isConstrainedEvent(e);
Graph graph = getGraphComponent().getGraph();
if (constrainedEvent && first != null) {
int x = e.getX();
int y = e.getY();
// ==============start==============
mxCell cell = (mxCell) graph.getSelectionCell();
if (graph.getModel().isBoundaryEvent(cell)) {
mxCell parent = (mxCell) graph.getModel().getParent(cell);
Rectangle rect = graph.getView().getState(parent).getRectangle();
Rectangle eventRect = graph.getView().getState(cell).getRectangle();
if (Math.abs(e.getX() - first.x) > Math.abs(e.getY() - first.y)) {
if (first.y - eventRect.getHeight() / 2 <= rect.getY() || first.y + eventRect.getHeight() / 2 >= (rect.getY() + rect.getHeight())) {
if (x > (rect.getX() + rect.getWidth())) {
x = (int) ((rect.getX() + rect.getWidth()));
} else if (x < rect.getX()) {
x = (int) (rect.getX());
}
y = first.y;
} else {
x = first.x;
y = first.y;
}
} else {
if (first.x - eventRect.getWidth() / 2 <= rect.getX() || first.x + eventRect.getWidth() / 2 >= (rect.getX() + rect.getWidth())) {
if (y > (rect.getY() + rect.getHeight())) {
y = (int) ((rect.getY() + rect.getHeight()));
} else if (y < rect.getY()) {
y = (int) (rect.getY());
}
x = first.x;
} else {
x = first.x;
y = first.y;
}
}
} else if (graph.getModel().isMessage(cell)) {
mxCell parent = (mxCell) graph.getModel().getParent(cell);
if (graph.getModel().isMessageFlow(parent)) {
mxCellState state = graph.getView().getState(parent);
double scale = graph.getView().getScale();
List points = new ArrayList(state.getAbsolutePoints());
mxPoint[] p = points.toArray(new mxPoint[points.size()]);
Rectangle rect = state.getRectangle();
if (x > (rect.getX() + rect.getWidth())) {
x = (int) ((rect.getX() + rect.getWidth()));
} else if (x < rect.getX()) {
x = (int) (rect.getX());
} else {
y = (int) p[1].getY();
}
if (y > (rect.getY() + rect.getHeight())) {
y = (int) ((rect.getY() + rect.getHeight()));
} else if (y < rect.getY()) {
y = (int) (rect.getY());
}
if (Math.abs(x - p[0].getX()) < 5 * scale) {
if (p[0].getY() > p[1].getY()) {
if (y < p[1].getY()) {
y = (int) p[1].getY();
}
} else {
if (y > p[1].getY()) {
y = (int) p[1].getY();
}
}
} else if (Math.abs(x - p[2].getX()) < 5 * scale) {
if (p[p.length - 1].getY() > p[p.length - 2].getY()) {
if (y < p[p.length - 2].getY()) {
y = (int) p[p.length - 2].getY();
}
} else if ((int) p[p.length - 1].getY() == (int) p[p.length - 2].getY()) {
y = (int) p[p.length - 2].getY();
} else if (p[p.length - 1].getY() < p[p.length - 2].getY()) {
if (y > p[p.length - 2].getY()) {
y = (int) p[p.length - 2].getY();
}
} else if (y > p[p.length - 1].getY()) {
y = (int) p[p.length - 2].getY();
}
}
if ((int) p[0].getX() == (int) p[p.length - 1].getX()) {
x = first.x;
}
}
} else if (graph.getModel().isPool(cell)) {
if (graph.isVerticalSwimlane(cell)) {
y = first.y;
} else {
x = first.x;
}
} else {
if (Math.abs(e.getX() - first.x) > Math.abs(e.getY() - first.y)) {
y = first.y;
} else {
x = first.x;
}
}
// ==============end================
e = new MouseEvent(e.getComponent(), e.getID(), e.getWhen(), e.getModifiers(), x, y, e.getClickCount(), e.isPopupTrigger(), e.getButton());
}
if (isVisible() && isMarkerEnabled()) {
marker.process(e);
}
if (first != null) {
if (movePreview.isActive()) {
double dx = e.getX() - first.x;
double dy = e.getY() - first.y;
if (graphComponent.isGridEnabledEvent(e)) {
dx = graph.snap(dx);
dy = graph.snap(dy);
}
boolean clone = isCloneEnabled() && graphComponent.isCloneEvent(e);
movePreview.update(e, dx, dy, clone);
e.consume();
} else if (cellBounds != null) {
double dx = e.getX() - first.x;
double dy = e.getY() - first.y;
if (previewBounds != null) {
setPreviewBounds(new Rectangle(getPreviewLocation(e, gridEnabledEvent), previewBounds.getSize()));
}
if (!isVisible() && graphComponent.isSignificant(dx, dy)) {
if (imagePreview && dragImage == null && !graphComponent.isDragEnabled()) {
updateDragImage(cells);
}
setVisible(true);
}
e.consume();
}
}
}
}
public void mouseReleased(MouseEvent e) {
if (graphComponent.isEnabled() && isEnabled() && !e.isConsumed()) {
Graph graph = getGraphComponent().getGraph();
double dx = 0;
double dy = 0;
if (first != null && (cellBounds != null || movePreview.isActive())) {
double scale = graph.getView().getScale();
mxPoint trans = graph.getView().getTranslate();
// TODO: Simplify math below, this was copy pasted from
// getPreviewLocation with the rounding removed
dx = e.getX() - first.x;
dy = e.getY() - first.y;
if (cellBounds != null && bbox != null) {
double dxg = ((cellBounds.getX() + dx) / scale) - trans.getX();
double dyg = ((cellBounds.getY() + dy) / scale) - trans.getY();
if (gridEnabledEvent) {
dxg = graph.snap(dxg);
dyg = graph.snap(dyg);
}
double x = ((dxg + trans.getX()) * scale) + (bbox.getX()) - (cellBounds.getX());
double y = ((dyg + trans.getY()) * scale) + (bbox.getY()) - (cellBounds.getY());
dx = Math.round((x - bbox.getX()) / scale);
dy = Math.round((y - bbox.getY()) / scale);
}
}
if (first == null || !graphComponent.isSignificant(e.getX() - first.x, e.getY() - first.y)) {
// Delayed handling of selection
if (cell != null && !e.isPopupTrigger() && isSelectEnabled() && (first != null || !isMoveEnabled())) {
graphComponent.selectCellForEvent(cell, e);
}
// Delayed folding for cell that was initially under the mouse
if (graphComponent.isFoldingEnabled() && graphComponent.hitFoldingIcon(initialCell, e.getX(), e.getY())) {
fold(initialCell);
} else {
// Handles selection if no cell was initially under the mouse
Object tmp = graphComponent.getCellAt(e.getX(), e.getY(), graphComponent.isSwimlaneSelectionEnabled());
if (cell == null && first == null) {
if (tmp == null) {
if (!graphComponent.isToggleEvent(e)) {
graph.clearSelection();
}
} else if (graph.isSwimlane(tmp)
&& graphComponent.getCanvas().hitSwimlaneContent(graphComponent, graph.getView().getState(tmp), e.getX(), e.getY())) {
graphComponent.selectCellForEvent(tmp, e);
}
}
if (graphComponent.isFoldingEnabled() && graphComponent.hitFoldingIcon(tmp, e.getX(), e.getY())) {
fold(tmp);
e.consume();
}
}
} else if (movePreview.isActive()) {
if (graphComponent.isConstrainedEvent(e)) {
if (Math.abs(dx) > Math.abs(dy)) {
dy = 0;
} else {
dx = 0;
}
}
mxCellState markedState = marker.getMarkedState();
Object target = (markedState != null) ? markedState.getCell() : null;
// FIXME: Cell is null if selection was carried out, need other variable
// trace("cell", cell);
if (target == null && isRemoveCellsFromParent() && shouldRemoveCellFromParent(graph.getModel().getParent(initialCell), cells, e)) {
target = graph.getDefaultParent();
}
boolean clone = isCloneEnabled() && graphComponent.isCloneEvent(e);
Object[] result = movePreview.stop(true, e, dx, dy, clone, target);
if (cells != result) {
graph.setSelectionCells(result);
}
e.consume();
} else if (isVisible()) {
// ==============start==============
if (constrainedEvent) {
mxCell cell = (mxCell) graph.getSelectionCell();
if (graph.getModel().isBoundaryEvent(cell)) {
mxCell parent = (mxCell) graph.getModel().getParent(cell);
Rectangle rect = graph.getView().getState(parent).getRectangle();
mxGeometry geo = cell.getGeometry();
mxPoint eventOffset = geo.getOffset();
if (Math.abs(dx) > Math.abs(dy)) {
if (first.x + dx > rect.getX() + rect.getWidth()) {
dx = rect.getX() + rect.getWidth() - first.x;
} else if (first.x + dx < rect.getX()) {
dx = rect.getX() - first.x;
}
dy = 0;
if (eventOffset.getY() < -parent.getGeometry().getHeight() / 2) { // align subprocess top
geo.setY(0);
eventOffset.setY(-geo.getWidth() / 2);
} else if (geo.getY() == 0) {
if (geo.getX() == 1) {
geo.setX(0);
if (eventOffset.getY() > 0) {
geo.setY(1);
eventOffset.setY(-geo.getWidth() / 2);
}
eventOffset.setX(parent.getGeometry().getWidth() + eventOffset.getX());
} else {
if (eventOffset.getY() > 0) {
geo.setY(1);
}
eventOffset.setY(-geo.getWidth() / 2);
}
} else { // align subprocess bottom
geo.setY(1);
eventOffset.setY(-geo.getWidth() / 2);
}
} else {
if (first.y + dy > rect.getY() + rect.getHeight()) {
dy = rect.getY() + rect.getHeight() - first.y;
} else if (first.y + dy < rect.getY()) {
dy = rect.getY() - first.y;
}
dx = 0;
if (eventOffset.getX() > 0) { // align subprocess right
geo.setX(1);
eventOffset.setX(-geo.getWidth() / 2);
if (geo.getY() == 1) {
geo.setY(0);
eventOffset.setY(parent.getGeometry().getHeight() + eventOffset.getY());
}
} else if (geo.getX() == 1) {
} else { // align subprocess left
geo.setX(0);
eventOffset.setX(-geo.getWidth() / 2);
if (geo.getY() == 1) {
geo.setY(0);
eventOffset.setY(parent.getGeometry().getHeight() + eventOffset.getY());
}
}
}
geo.setOffset(eventOffset);
geo.setAlternateBounds(null);
graph.getModel().setGeometry(cell, geo);
} else if (graph.getModel().isMessage(cell)) {
mxCell parent = (mxCell) graph.getModel().getParent(cell);
if (graph.getModel().isMessageFlow(parent)) {
mxCellState state = graph.getView().getState(parent);
double scale = graph.getView().getScale();
List points = new ArrayList(state.getAbsolutePoints());
mxPoint[] p = points.toArray(new mxPoint[points.size()]);
Rectangle rect = graph.getView().getState(parent).getRectangle();
if (first.x + dx > rect.getX() + rect.getWidth()) {
dx = rect.getX() + rect.getWidth() - first.x;
} else if (first.x + dx < rect.getX()) {
dx = rect.getX() - first.x;
} else {
dy = (int) p[1].getY() - first.y;
}
if (first.y + dy > rect.getY() + rect.getHeight()) {
dy = rect.getY() + rect.getHeight() - first.y;
} else if (first.y + dy < rect.getY()) {
dy = rect.getY() - first.y;
}
if (Math.abs(first.x + dx - p[0].getX()) < 5 * scale) {
if (p[0].getY() > p[1].getY()) {
if (first.y + dy < p[1].getY()) {
dy = p[1].getY() - first.y;
}
} else {
if (first.y + dy > p[1].getY()) {
dy = p[1].getY() - first.y;
}
}
} else if (Math.abs(first.x + dx - p[2].getX()) < 5 * scale) {
if (p[p.length - 1].getY() > p[p.length - 2].getY()) {
if (first.y + dy < p[p.length - 2].getY()) {
dy = p[p.length - 2].getY() - first.y;
}
} else if ((int) p[p.length - 1].getY() == (int) p[p.length - 2].getY()) {
dy = p[p.length - 2].getY() - first.y;
} else if (p[p.length - 1].getY() < p[p.length - 2].getY()) {
if (first.y + dy > p[p.length - 2].getY()) {
dy = p[p.length - 2].getY() - first.y;
}
} else if (first.y + dy > p[p.length - 1].getY()) {
dy = (int) p[p.length - 2].getY() - first.y;
}
}
if ((int) p[0].getX() == (int) p[p.length - 1].getX()) {
dx = 0;
}
}
} else if (graph.getModel().isPool(cell)) {
if (graph.isVerticalSwimlane(cell)) {
dy = 0;
} else {
dx = 0;
}
} else {
if (Math.abs(dx) > Math.abs(dy)) {
dy = 0;
} else {
dx = 0;
}
}
}
// ==============end================
mxCellState targetState = marker.getValidState();
Object target = (targetState != null) ? targetState.getCell() : null;
if (graph.isSplitEnabled() && graph.isSplitTarget(target, cells)) {
graph.splitEdge(target, cells, dx, dy);
} else {
moveCells(cells, dx, dy, target, e);
}
e.consume();
}
}
reset();
}
public void paint(Graphics g) {
if (isVisible() && previewBounds != null) {
if (dragImage != null) {
// LATER: Clipping with mxUtils doesnt fix the problem
// of the drawImage being painted over the scrollbars
Graphics2D tmp = (Graphics2D) g.create();
if (graphComponent.getPreviewAlpha() < 1) {
tmp.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, graphComponent.getPreviewAlpha()));
}
tmp.drawImage(dragImage.getImage(), previewBounds.x, previewBounds.y, dragImage.getIconWidth(), dragImage.getIconHeight(), null);
// ==============start==============
if (cells == null || cells != null && cells.length == 1) {
if (Constants.SETTINGS.getProperty("showAuxiliary", "0").equals("1")) {
getGraphComponent().paintAuxiliaryLines(tmp, previewBounds);
}
}
// ==============end================
tmp.dispose();
} else if (!imagePreview) {
mxSwingConstants.PREVIEW_BORDER.paintBorder(graphComponent, g, previewBounds.x, previewBounds.y, previewBounds.width, previewBounds.height);
}
}
}
protected Point getPreviewLocation(MouseEvent e, boolean gridEnabled) {
int x = 0;
int y = 0;
if (first != null && cellBounds != null) {
mxGraph graph = graphComponent.getGraph();
double scale = graph.getView().getScale();
mxPoint trans = graph.getView().getTranslate();
// LATER: Drag image _size_ depends on the initial position and may sometimes
// not align with the grid when dragging. This is because the rounding of the width
// and height at the initial position may be different than that at the current
// position as the left and bottom side of the shape must align to the grid lines.
// Only fix is a full repaint of the drag cells at each new mouse location.
double dx = e.getX() - first.x;
double dy = e.getY() - first.y;
double dxg = ((cellBounds.getX() + dx) / scale) - trans.getX();
double dyg = ((cellBounds.getY() + dy) / scale) - trans.getY();
if (gridEnabled) {
dxg = graph.snap(dxg);
dyg = graph.snap(dyg);
}
// ==============start==============
x = (int) Math.round((dxg + trans.getX()) * scale);
y = (int) Math.round((dyg + trans.getY()) * scale);
// ==============end================
}
return new Point(x, y);
}
public void setPreviewBounds(Rectangle bounds) {
if ((bounds == null && previewBounds != null) || (bounds != null && previewBounds == null)
|| (bounds != null && previewBounds != null && !bounds.equals(previewBounds))) {
Rectangle dirty = null;
if (isVisible()) {
dirty = previewBounds;
if (dirty != null) {
dirty.add(bounds);
} else {
dirty = bounds;
}
}
previewBounds = bounds;
if (dirty != null) {
graphComponent.getGraphControl().repaint(dirty.x - 1, dirty.y - 1, dirty.width + 2, dirty.height + 2);
}
// ==============start==============
if (previewBounds != null) {
repaintAuxiliaryArea(previewBounds);
}
// ==============end================
}
}
public void reset() {
super.reset();
// ==============start==============
if (previewBounds != null) {
repaintAuxiliaryArea(previewBounds);
}
// ==============end================
}
protected void repaintAuxiliaryArea(Rectangle bounds) {
if (Constants.SETTINGS.getProperty("showAuxiliary", "0").equals("1")) {
mxGraphControl graphControl = graphComponent.getGraphControl();
graphControl.repaint(bounds.x - 1, 0, bounds.width + 2, graphControl.getHeight());
graphControl.repaint(0, bounds.y - 1, graphControl.getWidth(), bounds.height + 2);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy