Java tutorial
/** * Copyright (c) 2015 Mashin (http://mashin.io). All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.mashin.oep.parts; import io.mashin.oep.figures.NodeFigure; import io.mashin.oep.figures.TerminalConnectionAnchor; import io.mashin.oep.model.ModelElement; import io.mashin.oep.model.commands.node.CustomActionNodeXMLEditCommand; import io.mashin.oep.model.connection.WorkflowConnection; import io.mashin.oep.model.editPolicies.NodeComponentEditPolicy; import io.mashin.oep.model.editPolicies.NodeGraphicalNodeEditPolicy; import io.mashin.oep.model.editPolicies.NodeLabelDirectEditPolicy; import io.mashin.oep.model.node.Node; import io.mashin.oep.model.node.action.extended.CustomActionNode; import io.mashin.oep.model.terminal.FanInTerminal; import io.mashin.oep.model.terminal.FanOutTerminal; import io.mashin.oep.model.terminal.NoInputTerminal; import io.mashin.oep.model.terminal.NoOutputTerminal; import io.mashin.oep.model.terminal.SingleOutputTerminal; import io.mashin.oep.model.terminal.Terminal; import io.mashin.oep.ui.editor.XMLEditor; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.StringWriter; import java.util.ArrayList; import java.util.List; import org.dom4j.DocumentHelper; import org.dom4j.io.OutputFormat; import org.dom4j.io.XMLWriter; import org.eclipse.draw2d.ConnectionAnchor; import org.eclipse.draw2d.IFigure; import org.eclipse.draw2d.Label; import org.eclipse.draw2d.geometry.Point; import org.eclipse.draw2d.geometry.Rectangle; import org.eclipse.gef.CompoundSnapToHelper; import org.eclipse.gef.ConnectionEditPart; import org.eclipse.gef.EditPart; import org.eclipse.gef.EditPolicy; import org.eclipse.gef.GraphicalEditPart; import org.eclipse.gef.NodeEditPart; import org.eclipse.gef.Request; import org.eclipse.gef.RequestConstants; import org.eclipse.gef.SnapToGeometry; import org.eclipse.gef.SnapToGrid; import org.eclipse.gef.SnapToHelper; import org.eclipse.gef.editparts.AbstractGraphicalEditPart; import org.eclipse.gef.editpolicies.SnapFeedbackPolicy; import org.eclipse.gef.requests.DropRequest; import org.eclipse.jface.viewers.TextCellEditor; public class WorkflowNodeEditPart extends AbstractGraphicalEditPart implements PropertyChangeListener, NodeEditPart { /** * Upon activation, attach to the model element as a property change listener. */ @Override public void activate() { if (!isActive()) { super.activate(); ((ModelElement) getModel()).addPropertyChangeListener(this); } } @Override protected void createEditPolicies() { // allow direct edit of node label installEditPolicy(EditPolicy.DIRECT_EDIT_ROLE, new NodeLabelDirectEditPolicy()); // allow removal of the associated model element installEditPolicy(EditPolicy.COMPONENT_ROLE, new NodeComponentEditPolicy()); // allow the creation of connections and // and the reconnection of connections between Shape instances installEditPolicy(EditPolicy.GRAPHICAL_NODE_ROLE, new NodeGraphicalNodeEditPolicy()); // allow snapping installEditPolicy("Snap Feedback", new SnapFeedbackPolicy()); } @Override public void performRequest(Request req) { if (req.getType() == RequestConstants.REQ_DIRECT_EDIT) { performDirectEditing(); } else if (req.getType() == RequestConstants.REQ_OPEN) { performOpen(); } else { super.performRequest(req); } } private void performDirectEditing() { Label label = ((NodeFigure) getFigure()).getLabelFigure(); NodeLabelDirectEditManager manager = new NodeLabelDirectEditManager(this, TextCellEditor.class, new NodeLabelCellEditorLocator(label), label); manager.show(); } private void performOpen() { if (getCastedModel() instanceof CustomActionNode) { CustomActionNode customActionNode = (CustomActionNode) getCastedModel(); String customActionNodeXML = ""; try { StringWriter stringWriter = new StringWriter(); XMLWriter writer = new XMLWriter(stringWriter, OutputFormat.createPrettyPrint()); writer.write(DocumentHelper .parseText((String) customActionNode.getPropertyValue(CustomActionNode.PROP_XML)) .getRootElement()); writer.flush(); customActionNodeXML = stringWriter.toString(); } catch (Exception e) { e.printStackTrace(); customActionNodeXML = (String) customActionNode.getPropertyValue(CustomActionNode.PROP_XML); } XMLEditor.getInstance().open(customActionNode, customActionNodeXML, customActionNode.getName(), xml -> getViewer().getEditDomain().getCommandStack() .execute(new CustomActionNodeXMLEditCommand(customActionNode, xml))); } } @Override protected IFigure createFigure() { Node node = getCastedModel(); NodeFigure nodeFigure = new NodeFigure(node.getNodeType()); nodeFigure.setLocation(node.getPosition()); List<Terminal> terminals = node.getTerminals(); for (Terminal terminal : terminals) { int terminalConnectionAnchorType = TerminalConnectionAnchor.TYPE_FANIN; if (terminal instanceof FanInTerminal) { terminalConnectionAnchorType = TerminalConnectionAnchor.TYPE_FANIN; } else if (terminal instanceof SingleOutputTerminal) { terminalConnectionAnchorType = TerminalConnectionAnchor.TYPE_OUT; } else if (terminal instanceof FanOutTerminal) { terminalConnectionAnchorType = TerminalConnectionAnchor.TYPE_FANOUT; } else if (terminal instanceof NoInputTerminal) { terminalConnectionAnchorType = TerminalConnectionAnchor.TYPE_NOIN; } else if (terminal instanceof NoOutputTerminal) { terminalConnectionAnchorType = TerminalConnectionAnchor.TYPE_NOOUT; } nodeFigure.addConnectionAnchor( new TerminalConnectionAnchor(nodeFigure, terminalConnectionAnchorType, terminal.getLabel())); } return nodeFigure; } // /** // * Return a IFigure depending on the instance of the current model element. // * This allows this EditPart to be used for all sublasses of Node. // */ // private IFigure createFigureForModel() { // RectangleFigure rectangleFigure = new RectangleFigure(); // rectangleFigure.setPreferredSize(30, 40); // rectangleFigure.setLocation(getCastedModel().getPosition()); // rectangleFigure.setSize(rectangleFigure.getPreferredSize()); // rectangleFigure.setOpaque(true); // rectangleFigure.setBackgroundColor(ColorConstants.lightGray); // return rectangleFigure; // } /** * Upon deactivation, detach from the model element as a property change * listener. */ @Override public void deactivate() { if (isActive()) { super.deactivate(); ((ModelElement) getModel()).removePropertyChangeListener(this); } } private Node getCastedModel() { return (Node) getModel(); } private NodeFigure getCastedFigure() { return (NodeFigure) getFigure(); } @Override protected List<WorkflowConnection> getModelSourceConnections() { return getCastedModel().getSourceConnections(); } @Override protected List<WorkflowConnection> getModelTargetConnections() { return getCastedModel().getTargetConnections(); } @Override public ConnectionAnchor getSourceConnectionAnchor(ConnectionEditPart connection) { return getCastedFigure() .getConnectionAnchor(((WorkflowConnection) connection.getModel()).getSourceTerminal().getLabel()); } @Override public ConnectionAnchor getSourceConnectionAnchor(Request request) { Point pt = new Point(((DropRequest) request).getLocation()); return getCastedFigure().getSourceConnectionAnchorAt(pt); } @Override public ConnectionAnchor getTargetConnectionAnchor(ConnectionEditPart connection) { return getCastedFigure() .getConnectionAnchor(((WorkflowConnection) connection.getModel()).getTargetTerminal().getLabel()); } @Override public ConnectionAnchor getTargetConnectionAnchor(Request request) { Point pt = new Point(((DropRequest) request).getLocation()); return getCastedFigure().getTargetConnectionAnchorAt(pt); } @Override public EditPart getTargetEditPart(Request request) { return super.getTargetEditPart(request); } @Override public void propertyChange(PropertyChangeEvent evt) { String prop = evt.getPropertyName(); switch (prop) { case Node.PROP_POS: case Node.PROP_NODE_NAME: refreshVisuals(); break; case Node.PROP_CONNECTION_SOURCE: refreshSourceConnections(); break; case Node.PROP_CONNECTION_TARGET: refreshTargetConnections(); break; } } @Override protected void refreshVisuals() { NodeFigure nodeFigure = getCastedFigure(); Node nodeModel = getCastedModel(); nodeFigure.setLabel(nodeModel.getName()); // notify parent container of changed position & location // if this line is removed, the XYLayoutManager used by the parent // container // (the Figure of the WorkflowEditPart), will not know the bounds // of this figure // and will not draw it correctly. Rectangle bounds = new Rectangle(nodeModel.getPosition(), nodeFigure.getSize()); ((GraphicalEditPart) getParent()).setLayoutConstraint(this, nodeFigure, bounds); } @Override @SuppressWarnings("rawtypes") public Object getAdapter(Class key) { if (key == SnapToHelper.class) { List<SnapToHelper> helpers = new ArrayList<>(); if (Boolean.TRUE.equals(getViewer().getProperty(SnapToGeometry.PROPERTY_SNAP_ENABLED))) { helpers.add(new SnapToGeometry(this)); } if (Boolean.TRUE.equals(getViewer().getProperty(SnapToGrid.PROPERTY_GRID_ENABLED))) { helpers.add(new SnapToGrid(this)); } if (helpers.size() == 0) { return null; } else { return new CompoundSnapToHelper(helpers.toArray(new SnapToHelper[0])); } } return super.getAdapter(key); } }