All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.yaoqiang.graph.swing.GraphComponent Maven / Gradle / Ivy

There is a newer version: 2.2.18
Show newest version
package org.yaoqiang.graph.swing;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.awt.event.MouseEvent;
import java.awt.print.PageFormat;
import java.util.EventObject;

import javax.swing.ImageIcon;
import javax.swing.JOptionPane;

import org.w3c.dom.Document;
import org.yaoqiang.bpmn.model.elements.activities.Activity;
import org.yaoqiang.bpmn.model.elements.activities.AdHocSubProcess;
import org.yaoqiang.bpmn.model.elements.choreographyactivities.ChoreographyActivity;
import org.yaoqiang.bpmn.model.elements.core.common.FlowNode;
import org.yaoqiang.bpmn.model.elements.events.BoundaryEvent;
import org.yaoqiang.graph.handler.ConnectionHandler;
import org.yaoqiang.graph.handler.GraphHandler;
import org.yaoqiang.graph.model.GraphModel;
import org.yaoqiang.graph.util.GraphUtils;
import org.yaoqiang.graph.view.Graph;
import org.yaoqiang.util.Constants;
import org.yaoqiang.util.Resources;

import com.mxgraph.io.mxCodec;
import com.mxgraph.model.mxICell;
import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.swing.view.mxICellEditor;
import com.mxgraph.util.mxPoint;
import com.mxgraph.util.mxUtils;
import com.mxgraph.view.mxCellState;

/**
 * GraphComponent
 * 
 * @author Shi Yaoqiang([email protected])
 */
public class GraphComponent extends mxGraphComponent {

	private static final long serialVersionUID = 5582918475032396064L;

	protected Point popupPoint;

	protected Point pasteToPoint;

	protected Object lastViewRoot;

	public GraphComponent(Graph graph) {
		super(graph);
		// Sets switches typically used in an editor
		setPageVisible(true);
		setVerticalPageCount(getGraph().getModel().getPageCount());
		setHorizontalPageCount(getGraph().getModel().getHorizontalPageCount());
		setGridVisible(Constants.SETTINGS.getProperty("showGrid", "1").equals("1"));
		setGridStyle(Integer.parseInt(Constants.SETTINGS.getProperty("gridstyle", "3")));
		setGridColor(mxUtils.parseColor(Constants.SETTINGS.getProperty("gridColor", "#c0c0c0")));
		setToolTips(true);
		setZoomFactor(1.05);
		setTolerance(2);
		setZoomPolicy(mxGraphComponent.ZOOM_POLICY_PAGE);
		setKeepSelectionVisibleOnZoom(true);
		setDragEnabled(false);
		setPreferPageSize(true);
		setEnterStopsCellEditing(true);
		getConnectionHandler().setHandleEnabled(true);
		getConnectionHandler().setCreateTarget(true);
		// setTripleBuffered(true);
		// getGraphHandler().setRemoveCellsFromParent(false);

		if (Constants.SETTINGS.getProperty("showRulers", "1").equals("1")) {
			setColumnHeaderView(new Ruler(this, Ruler.ORIENTATION_HORIZONTAL));
			setRowHeaderView(new Ruler(this, Ruler.ORIENTATION_VERTICAL));
		}

		// Loads the defalt stylesheet from an external file
		mxCodec codec = new mxCodec();
		Document doc = mxUtils.loadDocument(GraphComponent.class.getResource(Constants.DEFAULT_STYLE_XML).toString());
		codec.decode(doc.getDocumentElement(), graph.getStylesheet());

		// Sets PageFormat
		Constants.PAGE_WIDTH = Double.parseDouble(Constants.SETTINGS.getProperty("pageWidth", String.valueOf(11.7 * 72)));
		Constants.PAGE_HEIGHT = Double.parseDouble(Constants.SETTINGS.getProperty("pageHeight", String.valueOf(8.3 * 72)));

		PageFormat pageFormat = getGraph().getModel().setDefaultPageFormat();
		setPageFormat(pageFormat);

		Constants.SWIMLANE_WIDTH = (int) (pageFormat.getWidth() * 1.25 + (getGraph().getModel().getHorizontalPageCount() - 1)
				* (Constants.SWIMLANE_START_POINT + pageFormat.getWidth() * 1.25));

		Constants.SWIMLANE_HEIGHT = (int) (pageFormat.getHeight() * 1.2 + (getGraph().getModel().getPageCount() - 1)
				* (Constants.SWIMLANE_START_POINT + pageFormat.getHeight() * 1.2));

		// Sets the background to white
		getViewport().setOpaque(true);
		getViewport().setBackground(Color.WHITE);
	}

	public Graph getGraph() {
		return (Graph) graph;
	}

	public Point getPopupPoint() {
		return popupPoint;
	}

	public void setPopupPoint(Point popupPoint) {
		this.popupPoint = popupPoint;
	}

	public Point getPasteToPoint() {
		return pasteToPoint;
	}

	public void setPasteToPoint(Point pasteToPoint) {
		this.pasteToPoint = pasteToPoint;
	}

	public Object getLastViewRoot() {
		return lastViewRoot;
	}

	public void setLastViewRoot(Object lastViewRoot) {
		this.lastViewRoot = lastViewRoot;
	}

	protected ConnectionHandler createConnectionHandler() {
		return new ConnectionHandler(this);
	}

	protected GraphHandler createGraphHandler() {
		return new GraphHandler(this);
	}

	protected mxICellEditor createCellEditor() {
		return new CellEditor(this);
	}

	public Object[] importCells(Object[] cells, double dx, double dy, Object target, Point location) {
		if (cells[0] instanceof mxICell) {
			mxICell dropCell = (mxICell) cells[0];
			Graph graph = getGraph();
			GraphModel model = graph.getModel();

			if ("org".equals(getName()) && !graph.isOrganizationElement(dropCell) || !"org".equals(getName()) && !"GraphEditor".equals(getName())
					&& graph.isOrganizationElement(dropCell)) {
				return null;
			}

			if (target == null) {
				target = graph.getCurrentRoot();
			}

			if (graph.isSwimlane(dropCell)) {
				if (target == null) {
					if (model.isLane(dropCell) || GraphUtils.hasSwimlane(graph, !graph.isVerticalSwimlane(dropCell))) {
						return null;
					}
				} else {
					if (graph.isSwimlane(target)) {
						if (model.isPool(dropCell) || (graph.isVerticalSwimlane(dropCell) && !graph.isVerticalSwimlane(target))
								|| (!graph.isVerticalSwimlane(dropCell) && graph.isVerticalSwimlane(target))) {
							return null;
						}
					} else {
						return null;
					}
				}
			} else {
				if (target == null && dropCell.getParent() == null && dropCell.getId() != null && dropCell.isVertex()) {
					if (graph.isChoreography(dropCell) || graph.isSubChoreography(dropCell)) {
						JOptionPane.showMessageDialog(null, Resources.get("WarningCopyPasteNotApplicableForChoreography"), "Not Applicable",
								JOptionPane.WARNING_MESSAGE);
						return null;
					}
					mxICell srcCell = (mxICell) getCellAt((int) dropCell.getGeometry().getX(), (int) dropCell.getGeometry().getY());
					if (getPasteToPoint() != null) {
						srcCell = (mxICell) getCellAt(getPasteToPoint().x, getPasteToPoint().y);
					}

					if (srcCell == null) {
						target = null;
					} else if (dropCell.getId().equals(srcCell.getId())) {
						target = model.getParent(srcCell);
					} else {
						if (model.isSubProcess(srcCell) || graph.isSwimlane(srcCell)) {
							target = srcCell;
						} else {
							target = model.getParent(srcCell);
						}
					}
				}
			}
			if (dropCell.isVertex() && !graph.isOrganizationElement(dropCell)) {
				if (Constants.SETTINGS.getProperty("labelWrap", "0").equals("1")) {
					model.setStyle(dropCell, dropCell.getStyle() + ";whiteSpace=wrap;");
					GraphUtils.setElementStyles(graph, "whiteSpace", "wrap", dropCell);
				}
			}
			if (dropCell.getValue() instanceof BoundaryEvent) {
				if (target == null || (!model.isTask(target) && !model.isSubProcess(target) && !model.isCallActivity(target))) {
					JOptionPane.showMessageDialog(null, Resources.get("WarningBoundaryEventMustBeAttachedToActivityBoundary"), "Validation Error!",
							JOptionPane.WARNING_MESSAGE);
					return null;
				}
			}
		}
		return graph.moveCells(cells, dx, dy, true, target, location);
	}

	public ImageIcon getFoldingIcon(mxCellState state) {
		if (state != null) {
			// ==============start==============
			if (getGraph().getModel().isCollapsedSubProcess(state.getCell())) {
				return new ImageIcon(GraphComponent.class.getResource("/org/yaoqiang/graph/shape/markers/subprocess.png"));
				// ==============end================
			} else {
				if (isFoldingEnabled() && !graph.getModel().isEdge(state.getCell())) {
					Object cell = state.getCell();
					boolean tmp = graph.isCellCollapsed(cell);

					if (graph.isCellFoldable(cell, !tmp)) {
						return (tmp) ? collapsedIcon : expandedIcon;
					}
				}
			}
		}

		return null;
	}

	public Rectangle getFoldingIconBounds(mxCellState state, ImageIcon icon) {
		if (getGraph().getModel().isCollapsedSubProcess(state.getCell())) {
			FlowNode flowNode = (FlowNode) ((mxICell) state.getCell()).getValue();
			double scale = getGraph().getView().getScale();
			Rectangle iconBounds = state.getRectangle();
			int imgWidth = (int) (32 * scale);
			int imgHeight = (int) (16 * scale);

			String compensationMarker = null;
			String loopMarker = null;

			if (flowNode instanceof Activity) {
				Activity subProcess = (Activity) flowNode;
				compensationMarker = subProcess.isForCompensation() ? "" : null;
				if (subProcess.getLoopCharacteristics() != null) {
					loopMarker = "";
				}
			} else if (flowNode instanceof ChoreographyActivity) {
				ChoreographyActivity subProcess = (ChoreographyActivity) flowNode;
				if (!subProcess.getLoopType().equals("None")) {
					loopMarker = "";
				}
			}

			if (flowNode instanceof AdHocSubProcess) {
				if (loopMarker != null || compensationMarker != null) {
					if (loopMarker != null && compensationMarker != null) {
						iconBounds.setRect(iconBounds.getX() + iconBounds.getWidth() / 2, iconBounds.getY() + iconBounds.getHeight() - imgHeight, imgWidth / 2,
								imgHeight);
					} else {
						iconBounds.setRect(iconBounds.getX() + (2 * iconBounds.getWidth() - imgWidth) / 4, iconBounds.getY() + iconBounds.getHeight()
								- imgHeight, imgWidth / 2, imgHeight);
					}
				} else {
					iconBounds.setRect(iconBounds.getX() + (iconBounds.getWidth() - imgWidth) / 2, iconBounds.getY() + iconBounds.getHeight() - imgHeight,
							imgWidth / 2, imgHeight);
				}
			} else {
				if (loopMarker != null || compensationMarker != null) {
					if (loopMarker != null && compensationMarker != null) {
						iconBounds.setRect(iconBounds.getX() + (2 * iconBounds.getWidth() + imgWidth) / 4, iconBounds.getY() + iconBounds.getHeight()
								- imgHeight, imgWidth / 2, imgHeight);
					} else {
						iconBounds.setRect(iconBounds.getX() + iconBounds.getWidth() / 2, iconBounds.getY() + iconBounds.getHeight() - imgHeight, imgWidth / 2,
								imgHeight);
					}
				} else {
					iconBounds.setRect(iconBounds.getX() + (2 * iconBounds.getWidth() - imgWidth) / 4, iconBounds.getY() + iconBounds.getHeight() - imgHeight,
							imgWidth / 2, imgHeight);
				}
			}
			return iconBounds;
		} else {
			return super.getFoldingIconBounds(state, icon);
		}

	}

	public boolean isGridEnabledEvent(MouseEvent event) {
		boolean enable = Constants.SETTINGS.getProperty("snapToGrid", "1").equals("1");
		return (event != null) ? enable ? !event.isAltDown() : event.isAltDown() : false;
	}

	public boolean isConstrainedEvent(MouseEvent event) {
		return (event != null) ? event.isShiftDown() || getGraph().getModel().isBoundaryEvent(graph.getSelectionCell())
				|| getGraph().getModel().isMessage(graph.getSelectionCell())
				&& getGraph().getModel().isMessageFlow(graph.getModel().getParent(graph.getSelectionCell())) || getGraph().isAutoPool(graph.getSelectionCell())
				: false;
	}

	public Object getEditingValue(Object cell, EventObject trigger) {
		if (getGraph().getModel().isGroupArtifact(cell) || getGraph().getModel().isDataStore(cell) || getGraph().getModel().isDataObject(cell)) {
			return getGraph().getModel().getValue(cell);
		}
		return graph.convertValueToString(cell);
	}

	public void startEditing() {
		Object cell = graph.getSelectionCell();
		if (getGraph().isChoreography(cell) || getGraph().isSubChoreography(cell)) {
			cell = GraphUtils.getChoreographyActivity(getGraph(), cell);
		}
		startEditingAtCell(cell);
	}

	protected Rectangle paintBackgroundPage(Graphics g) {
		mxPoint translate = graph.getView().getTranslate();
		double scale = graph.getView().getScale();
		// ==============start==============
		int x0 = (int) Math.round((translate.getX() + 28) * scale);
		int y0 = (int) Math.round((translate.getY() + 28) * scale);

		Dimension d = getPreferredSizeForPage();
		int w = (int) Math.round((d.width - 45) * scale);
		int h = (int) Math.round((d.height - 45) * scale);
		// ==============end================
		if (isPageVisible()) {
			// Draws the background behind the page
			Color c = getPageBackgroundColor();

			if (c != null) {
				g.setColor(c);
				mxUtils.fillClippedRect(g, 0, 0, getGraphControl().getWidth(), getGraphControl().getHeight());
			}

			// Draws the page drop shadow
			c = getPageShadowColor();

			if (c != null) {
				g.setColor(c);
				mxUtils.fillClippedRect(g, x0 + w, y0 + 6, 6, h - 6);
				mxUtils.fillClippedRect(g, x0 + 8, y0 + h, w - 2, 6);
			}

			// Draws the page
			Color bg = getBackground();

			if (getViewport().isOpaque()) {
				bg = getViewport().getBackground();
			}

			g.setColor(bg);
			mxUtils.fillClippedRect(g, x0 + 1, y0 + 1, w, h);

			// Draws the page border
			c = getPageBorderColor();

			if (c != null) {
				g.setColor(c);
				g.drawRect(x0, y0, w, h);
			}
		}

		if (isPageBreaksVisible() && (horizontalPageCount > 1 || verticalPageCount > 1)) {
			// Draws the pagebreaks
			// TODO: Use clipping
			Graphics2D g2 = (Graphics2D) g;
			Stroke previousStroke = g2.getStroke();

			g2.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, new float[] { 1, 2 }, 0));
			g2.setColor(pageBreakColor);

			for (int i = 1; i <= horizontalPageCount - 1; i++) {
				int dx = i * w / horizontalPageCount;
				g2.drawLine(x0 + dx, y0 + 1, x0 + dx, y0 + h);
			}

			for (int i = 1; i <= verticalPageCount - 1; i++) {
				int dy = i * h / verticalPageCount;
				g2.drawLine(x0 + 1, y0 + dy, x0 + w, y0 + dy);
			}

			// Restores the graphics
			g2.setStroke(previousStroke);
		}

		return new Rectangle(x0, y0, w, h);
	}

	public void paintAuxiliaryLines(Graphics2D g, Rectangle bounds) {
		g.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, new float[] { 30.0f, 3.0f, 2.0f, 3.0f }, 0.0f));
		g.setColor(Color.BLACK);
		g.drawLine(bounds.x, 0, bounds.x, graphControl.getHeight());
		g.drawLine(bounds.x + bounds.width / 2, 0, bounds.x + bounds.width / 2, graphControl.getHeight());
		g.drawLine(bounds.x + bounds.width, 0, bounds.x + bounds.width, graphControl.getHeight());
		g.drawLine(0, bounds.y, graphControl.getWidth(), bounds.y);
		g.drawLine(0, bounds.y + bounds.height / 2, graphControl.getWidth(), bounds.y + bounds.height / 2);
		g.drawLine(0, bounds.y + bounds.height, graphControl.getWidth(), bounds.y + bounds.height);
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy