blob: 93c8c4ae6be5a9479d07667db601710a9b3521cc [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015, 2016 Willink Transformations and others.
* All rights reserved. This program and the accompanying materials
* are 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:
* E.D.Willink - Initial API and implementation
*******************************************************************************/
package org.eclipse.qvtd.compiler.internal.qvtp2qvts.impl;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.Property;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.EdgeConnection;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.EdgeRole;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.NavigableEdge;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.Node;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.SchedulerConstants;
import org.eclipse.qvtd.compiler.internal.qvtp2qvts.Visitor;
import org.eclipse.qvtd.pivot.qvtbase.graphs.GraphStringBuilder;
import org.eclipse.qvtd.pivot.qvtbase.graphs.GraphStringBuilder.GraphNode;
import com.google.common.collect.Iterables;
public abstract class NavigableEdgeImpl extends EdgeImpl implements NavigableEdge
{
private @Nullable Property source2targetProperty = null; // null is only permitted during construction
/**
* Non-null if this edge is part of a bidirectional pair.
*/
private @Nullable NavigableEdge oppositeEdge = null;
/**
* True if this edge is the auto-created second half of a bidirectional pair.
*/
private boolean isSecondary = false;
private @Nullable EdgeConnection incomingConnection = null;
private @Nullable List<@NonNull EdgeConnection> outgoingConnections = null;
@Override
public <R> R accept(@NonNull Visitor<R> visitor) {
return visitor.visitNavigableEdge(this);
}
@Override
public final void addIncomingConnection(@NonNull EdgeConnection edgeConnection) {
assert incomingConnection == null;
assert Iterables.contains(edgeConnection.getTargetEdges(), this);
// assert edge.getRegion() == getRegion();
incomingConnection = edgeConnection;
}
@Override
public final void addOutgoingConnection(@NonNull EdgeConnection edgeConnection) {
assert Iterables.contains(edgeConnection.getSources(), this);
// assert edge.getRegion() == getRegion();
List<@NonNull EdgeConnection> outgoingConnections2 = outgoingConnections;
if (outgoingConnections2 == null) {
outgoingConnections = outgoingConnections2 = new ArrayList<@NonNull EdgeConnection>();
}
else {
assert !outgoingConnections2.contains(edgeConnection);
}
outgoingConnections2.add(edgeConnection);
}
@Override
public void appendEdgeAttributes(@NonNull GraphStringBuilder s, @NonNull GraphNode source, @NonNull GraphNode target) {
s.setColor(getColor());
@Nullable
NavigableEdge oppositeEdge2 = oppositeEdge;
if (oppositeEdge2 != null) {
String oppositeLabel = oppositeEdge2.getLabel();
if ((oppositeLabel != null) && !oppositeEdge2.getProperty().getName().equals(((Node)source).getClassDatumAnalysis().getCompleteClass().getName())) {
s.setTaillabel(oppositeLabel);
}
}
String label = getLabel();
if (label != null) {
s.setHeadlabel(label);
}
String style = getStyle();
if (style != null) {
s.setStyle(style);
}
if (!isSecondary() && (oppositeEdge2 != null)) {
s.setDir("both");
s.setArrowtail("vee");
}
s.setArrowhead("normal");
s.setPenwidth(getPenwidth());
s.appendAttributedEdge(source, this, target);
}
@Override
public void destroy() {
NavigableEdge oppositeEdge = this.oppositeEdge;
if (oppositeEdge != null) {
this.oppositeEdge = null;
oppositeEdge.destroy();
}
else {
super.destroy();
}
}
@Override
public @NonNull String getDisplayName() {
Property source2targetProperty2 = source2targetProperty;
if (source2targetProperty2 != null) {
org.eclipse.ocl.pivot.Class owningClass = source2targetProperty2.getOwningClass();
if (owningClass != null) {
return owningClass.getName() + "::" + source2targetProperty2.getName();
}
else {
return "" + source2targetProperty2.getName();
}
}
else {
return "null";
}
}
@Override
public @NonNull NavigableEdge getForwardEdge() {
if (isSecondary) {
assert oppositeEdge != null;
return oppositeEdge;
}
else {
return this;
}
}
@Override
public final @Nullable EdgeConnection getIncomingConnection() {
return incomingConnection;
}
@Override
public @Nullable String getLabel() {
@Nullable
Property source2targetProperty2 = source2targetProperty;
if (source2targetProperty2 == null) {
return "null";
}
else if (source2targetProperty2.eContainer() != null) {
return source2targetProperty2.getName() + "\\n" + SchedulerConstants.getMultiplicity(source2targetProperty2);
}
else {
return source2targetProperty2.getName();
}
}
@Override
public @Nullable NavigableEdge getOppositeEdge() {
return oppositeEdge;
}
@Override
public final @NonNull List<@NonNull EdgeConnection> getOutgoingConnections() {
return outgoingConnections != null ? outgoingConnections : SchedulerConstants.EMPTY_EDGE_CONNECTION_LIST;
}
@Override
public @NonNull Property getProperty() {
return ClassUtil.nonNullState(source2targetProperty);
}
protected void initialize(@NonNull EdgeRole edgeRole, @NonNull Node sourceNode, @NonNull Property source2targetProperty, @NonNull Node targetNode) {
initialize(edgeRole, sourceNode, source2targetProperty.getName(), targetNode);
setProperty(source2targetProperty);
}
protected void initializeOpposite(@NonNull NavigableEdgeImpl oppositeEdge) {
this.oppositeEdge = oppositeEdge;
oppositeEdge.oppositeEdge = this;
if (this.getProperty().isIsImplicit()) {
this.isSecondary = true;
}
else {
oppositeEdge.isSecondary = true;
}
}
@Override
public boolean isRequired() {
Node targetNode = getTarget();
Property property = getProperty();
if (targetNode.isExplicitNull()) {
return true; // ?? a degenerate typedElement.isIsRequired()
}
else if (property.isIsRequired()) {
return true;
}
else if (targetNode.isRequired()) {
return true;
}
else {
return false;
}
}
@Override
public boolean isSecondary() {
return isSecondary;
}
@Override
public final void removeIncomingConnection(@NonNull EdgeConnection edgeConnection) {
assert Iterables.contains(edgeConnection.getTargetEdges(), this);
// assert edge.getRegion() == getRegion();
assert incomingConnection != null;
incomingConnection = null;
}
@Override
public final void removeOutgoingConnection(@NonNull EdgeConnection edgeConnection) {
assert Iterables.contains(edgeConnection.getSources(), this);
// assert edge.getRegion() == getRegion();
List<EdgeConnection> outgoingConnections2 = outgoingConnections;
assert outgoingConnections2 != null;
@SuppressWarnings("unused")boolean wasRemoved = outgoingConnections2.remove(edgeConnection);
// assert wasRemoved; -- destroy subverts this
}
public void setProperty(Property source2targetProperty) {
this.source2targetProperty = source2targetProperty;
}
@Override
public void toGraph(@NonNull GraphStringBuilder s) {
if (isSecondary()) {
// Let primary draw a bidirectional edge
}
else if ((incomingConnection == null) && (outgoingConnections == null)) {
super.toGraph(s);
}
else {
appendEdgeWithNode(s);
}
}
// @Override
// public void setSource(@Nullable Node sourceNode) {
// assert (sourceNode == null) || !sourceNode.isOperation();
// super.setSource(sourceNode);
// }
// @Override
// public void setTarget(@Nullable Node targetNode) {
// assert (targetNode == null) || !targetNode.isOperation();
// super.setTarget(targetNode);
// }
}