/*******************************************************************************
* This program is made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Tomas Milata - initial API and implementation
******************************************************************************/
package org.jboss.tools.batch.ui.editor.internal.services.diagram.connection;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.sapphire.Element;
import org.eclipse.sapphire.Event;
import org.eclipse.sapphire.Listener;
import org.eclipse.sapphire.ReferenceValue;
import org.eclipse.sapphire.services.ReferenceService;
import org.eclipse.sapphire.ui.Point;
import org.eclipse.sapphire.ui.SapphireActionSystem;
import org.eclipse.sapphire.ui.diagram.ConnectionAddEvent;
import org.eclipse.sapphire.ui.diagram.ConnectionBendpointsEvent;
import org.eclipse.sapphire.ui.diagram.ConnectionDeleteEvent;
import org.eclipse.sapphire.ui.diagram.ConnectionEndpointsEvent;
import org.eclipse.sapphire.ui.diagram.DiagramConnectionPart;
import org.eclipse.sapphire.ui.diagram.def.IDiagramConnectionDef;
import org.eclipse.sapphire.ui.diagram.editor.DiagramNodePart;
import org.jboss.tools.batch.ui.editor.internal.model.FlowElement;
import org.jboss.tools.batch.ui.editor.internal.model.NextAttributeElement;
/**
* A custom implementation of Sapphire connection part to be used for connection
* using {@code next} attribute in the {@link BatchDiagramConnectionService}.
*
* @author Tomas Milata
*/
public class NextAttributeConnectionPart extends DiagramConnectionPart {
private NextAttributeElement srcElement;
private FlowElement targetElement;
private List<Point> bendpoints = new ArrayList<>();
private BatchDiagramConnectionEventHandler eventHandler;
private Listener listener;
private ReferenceService<?> referenceService;
private BatchDiagramConnectionService connectionService;
/**
*
* @param node1
* a {@code <step>}, {@code <split>} or {@code <flow>}
* @param node2
* a {@code <step>}, {@code <split>}, {@code <flow>} or a
* {@code <decision>}
* @param service
* a connection service that uses this part
* @param eventHandler
* for notification about changes
* @param srcElement
* @param targetElement
*/
public NextAttributeConnectionPart(NextAttributeElement srcElement, FlowElement targetElement,
BatchDiagramConnectionService service, BatchDiagramConnectionEventHandler eventHandler) {
this.srcElement = srcElement;
this.targetElement = targetElement;
this.connectionService = service;
this.eventHandler = eventHandler;
}
@Override
protected void init() {
initializeListeners();
eventHandler.onConnectionAddEvent(new ConnectionAddEvent(this));
}
/**
* Initializes listeners for changes of the target element.
*/
private void initializeListeners() {
ReferenceValue<String, FlowElement> reference = srcElement.getNext();
// may be null if id was not entered yet
if (reference.target() != null) {
// refresh, otherwise the reference changed event not fired
reference.target().refresh();
}
referenceService = reference.service(ReferenceService.class);
listener = new Listener() {
@Override
public void handle(Event event) {
FlowElement newTarget = srcElement.getNext().target();
if (newTarget == null) {
referenceService.detach(this);
eventHandler.onConnectionDeleteEvent(new ConnectionDeleteEvent(NextAttributeConnectionPart.this));
} else if (newTarget != targetElement) {
changeTargetElement(newTarget);
}
}
};
referenceService.attach(listener);
}
private void changeTargetElement(FlowElement newTarget) {
targetElement = newTarget;
srcElement.setNext(targetElement.getId().content());
removeAllBendpoints();
eventHandler.onConnectionEndpointsEvent(new ConnectionEndpointsEvent(this));
}
/**
* Declares action context so contexts so that actions are allowed for this
* part.
*/
@Override
public Set<String> getActionContexts() {
Set<String> contextSet = new HashSet<String>();
contextSet.add(SapphireActionSystem.CONTEXT_DIAGRAM_CONNECTION);
contextSet.add(SapphireActionSystem.CONTEXT_DIAGRAM_CONNECTION_HIDDEN);
return contextSet;
}
@Override
public boolean removable() {
return true;
}
@Override
public void remove() {
srcElement.setNext(null);
eventHandler.onConnectionDeleteEvent(new ConnectionDeleteEvent(this));
}
/**
* Creates a unique id using this part's id in the list of connections
* maintained by the connection service.
*/
@Override
public String getId() {
StringBuilder builder = new StringBuilder();
builder.append(BachtConnectionIdConst.NEXT_ATTRIBUTE_CONNECTION_ID);
builder.append(connectionService.list().indexOf(this));
return builder.toString();
}
/**
* @return {@link BachtConnectionIdConst.NEXT_ATTRIBUTE_CONNECTION_ID}
*/
@Override
public String getConnectionTypeId() {
return BachtConnectionIdConst.NEXT_ATTRIBUTE_CONNECTION_ID;
}
@Override
public IDiagramConnectionDef getConnectionDef() {
return (IDiagramConnectionDef) definition;
}
@Override
public DiagramConnectionPart reconnect(DiagramNodePart newSrc, DiagramNodePart newTargetNode) {
changeTargetElement((FlowElement) newTargetNode.getLocalModelElement());
return this;
}
/**
* Returns {@code false} as we do not need labels for this connection type.
*
* @return {@code false}
*/
@Override
public boolean canEditLabel() {
return false;
}
@Override
public List<Point> getBendpoints() {
return new ArrayList<>(bendpoints);
}
@Override
public void removeAllBendpoints() {
bendpoints.clear();
broadcast(new ConnectionBendpointsEvent(this));
}
@Override
public void resetBendpoints(List<Point> bendpoints) {
this.bendpoints = bendpoints;
broadcast(new ConnectionBendpointsEvent(this, true));
}
@Override
public void addBendpoint(int index, int x, int y) {
bendpoints.add(index, new Point(x, y));
broadcast(new ConnectionBendpointsEvent(this));
}
@Override
public void updateBendpoint(int index, int x, int y) {
bendpoints.set(index, new Point(x, y));
broadcast(new ConnectionBendpointsEvent(this));
}
@Override
public void removeBendpoint(int index) {
bendpoints.remove(index);
broadcast(new ConnectionBendpointsEvent(this));
}
/**
* Returns {@code null} as we do not need labels for this connection type.
*
* @return {@code null}
*/
@Override
public String getLabel() {
return null;
}
/**
* Does nothing as we do not need labels for this connection type.
*/
@Override
public void setLabel(String newValue) {
}
/**
* Returns {@code null} as we do not need labels for this connection type.
*
* @return {@code null}
*/
@Override
public Point getLabelPosition() {
return null;
}
/**
* Does nothing as we do not need labels for this connection type.
*/
@Override
public void setLabelPosition(Point newPos) {
}
@Override
public Element getEndpoint1() {
return srcElement;
}
@Override
public Element getEndpoint2() {
return targetElement;
}
}