blob: bfd5081a5813dc585671889b6e0c62b953a0915b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016, 2018 Willink Transformations and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* E.D.Willink - initial API and implementation
*******************************************************************************/
package org.eclipse.qvtd.pivot.qvtschedule.utilities;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.qvtd.pivot.qvtbase.graphs.DelegatingToGraphHelper;
import org.eclipse.qvtd.pivot.qvtbase.graphs.GraphStringBuilder;
import org.eclipse.qvtd.pivot.qvtbase.graphs.GraphStringBuilder.GraphElement;
import org.eclipse.qvtd.pivot.qvtbase.graphs.GraphStringBuilder.GraphNode;
import org.eclipse.qvtd.pivot.qvtbase.graphs.ToGraphHelper;
import org.eclipse.qvtd.pivot.qvtschedule.BasicPartition;
import org.eclipse.qvtd.pivot.qvtschedule.Connection;
import org.eclipse.qvtd.pivot.qvtschedule.ConnectionEnd;
import org.eclipse.qvtd.pivot.qvtschedule.ConnectionRole;
import org.eclipse.qvtd.pivot.qvtschedule.CyclicPartition;
import org.eclipse.qvtd.pivot.qvtschedule.Edge;
import org.eclipse.qvtd.pivot.qvtschedule.MappingPartition;
import org.eclipse.qvtd.pivot.qvtschedule.MappingRegion;
import org.eclipse.qvtd.pivot.qvtschedule.NavigableEdge;
import org.eclipse.qvtd.pivot.qvtschedule.Node;
import org.eclipse.qvtd.pivot.qvtschedule.OperationRegion;
import org.eclipse.qvtd.pivot.qvtschedule.Partition;
import org.eclipse.qvtd.pivot.qvtschedule.Region;
import org.eclipse.qvtd.pivot.qvtschedule.Role;
import org.eclipse.qvtd.pivot.qvtschedule.RootPartition;
import org.eclipse.qvtd.pivot.qvtschedule.RootRegion;
/**
* ToGraphPartitionVisitor refines ToGraphVisitor to display <<success>> nodes in the partition-specific form.
*/
public abstract class ToGraphPartitionVisitor extends AbstractToGraphVisitor
{
public static @NonNull AbstractToGraphVisitor createVisitor(@NonNull GraphStringBuilder s, boolean showInternals) {
if (showInternals) {
return new ShowInternals(s);
}
else {
return new HideInternals(s);
}
}
private static class HideInternals extends ToGraphPartitionVisitor
{
protected HideInternals(@NonNull GraphStringBuilder context) {
super(context);
}
@Override
protected void setScope(@Nullable Object scopeObject) {}
@Override
protected void showPartitionInternals(@NonNull Partition partition) {
setScope(null);
appendNode(partition);
}
@Override
protected void showRegionInternals(@NonNull Region region) {
setScope(null);
appendNode(region);
}
@Override
public @Nullable String visitConnection(@NonNull Connection connection) {
if (hasPartitions) { // Partition-to-Partition within RootRegion
appendNode(connection);
for (@NonNull Partition sourcePartition : connection.getSourcePartitions()) {
Partition mergedSourcePartition = QVTscheduleUtil.getMergedPartition(sourcePartition);
if (mergedSourcePartition == sourcePartition) {
appendEdge(sourcePartition, connection, connection);
}
}
Iterable<@NonNull Partition> targetPartitions = connection.getTargetPartitions();
for (@NonNull Partition targetPartition : targetPartitions) {
Partition mergedTargetPartition = QVTscheduleUtil.getMergedPartition(targetPartition);
if (mergedTargetPartition == targetPartition) {
Iterable<@NonNull ConnectionEnd> connectionEnds = connection.getTargetConnectionEnds(targetPartition);
for (@NonNull ConnectionEnd connectionEnd : connectionEnds) {
ConnectionRole connectionRole = connection.getTargetConnectionRole(targetPartition, connectionEnd);
appendEdge(connection, connectionRole, targetPartition);
}
}
}
}
else { // Region-to-Region within RootRegion
RootRegion rootRegion = connection.getOwningRootRegion();
appendNode(connection);
for (@NonNull Node sourceNode : connection.getSourceNodes()) {
Region sourceRegion = rootRegion.getNormalizedRegion(QVTscheduleUtil.getOwningRegion(sourceNode));
if (sourceRegion != null) {
appendEdge(sourceRegion, connection, connection);
}
}
for (@NonNull ConnectionEnd target : connection.getTargetEnds()) {
ConnectionRole role = connection.getTargetRole(target);
assert role != null;
Region targetRegion = rootRegion.getNormalizedRegion(QVTscheduleUtil.getOwningRegion(target));
if (targetRegion != null) {
appendEdge(connection, role, targetRegion);
}
}
}
return null;
}
}
private static class ShowInternals extends ToGraphPartitionVisitor
{
protected ShowInternals(@NonNull GraphStringBuilder context) {
super(context);
}
@Override
protected void setScope(@Nullable Object scopeObject) {
if (hasPartitions) {
context.setScope(scopeObject);
}
}
@Override
protected void showPartitionInternals(@NonNull Partition partition) {
setScope(partition);
context.setLabel(partition.getGraphName());
context.pushCluster();
for (@NonNull Node node : partition.getPartialNodes()) {
node.accept(this);
}
for (@NonNull Edge edge : partition.getPartialEdges()) {
edge.accept(this);
}
context.popCluster();
setScope(null);
}
@Override
protected void showRegionInternals(@NonNull Region region) {
context.setLabel(region.getGraphName());
context.pushCluster();
setScope(null);
for (@NonNull Node node : QVTscheduleUtil.getOwnedNodes(region)) {
node.accept(this);
}
for (@NonNull Edge edge : QVTscheduleUtil.getOwnedEdges(region)) {
edge.accept(this);
}
context.popCluster();
}
@Override
public @Nullable String visitConnection(@NonNull Connection connection) {
if (hasPartitions) { // Node-to-Node within Partition within RootRegion
setScope(null);
RootRegion rootRegion = connection.getOwningRootRegion();
appendNode(connection);
for (@NonNull ConnectionEnd sourceEnd : QVTscheduleUtil.getSourceEnds(connection)) {
Region sourceRegion = QVTscheduleUtil.getOwningRegion(sourceEnd);
Iterable<@NonNull MappingPartition> partitions = null;
if (sourceRegion instanceof MappingRegion) {
partitions = QVTscheduleUtil.getMappingPartitions(((MappingRegion)sourceRegion));
}
if (partitions != null) {
for (@NonNull Partition sourcePartition : partitions) {
Role sourceRole = QVTscheduleUtil.getRole(sourcePartition, sourceEnd);
if ((sourceRole != null) && !sourceRole.isChecked()) { // (sourceRole.isNew() || sourceRole.isLoaded())) {
Node sourceNode;
if (sourceEnd instanceof Edge) {
sourceNode = QVTscheduleUtil.getTargetNode((Edge) sourceEnd);
}
else {
sourceNode = (@NonNull Node) sourceEnd;
}
setScope(sourcePartition);
Iterable<@NonNull Node> sharedEdgeTargetNodes = QVTscheduleUtil.getSharedEdgeTargetNodes(sourcePartition, sourceNode);
if (sharedEdgeTargetNodes != null) {
for (@NonNull Node targetNode : sharedEdgeTargetNodes) {
ToGraphHelper sourceGraphHelper = new DelegatingToGraphHelper(this)
{
@Override
public void setColor(@NonNull GraphElement element) {
super.setColor(sourceNode);
}
};
context.appendEdge(sourceGraphHelper, sourceNode, connection, connection);
ToGraphHelper targetGraphHelper = new DelegatingToGraphHelper(this)
{
@Override
public void setColor(@NonNull GraphElement element) {
super.setColor(targetNode);
}
};
context.appendEdge(targetGraphHelper, connection, connection, targetNode);
}
}
else {
appendEdge(sourceNode, connection, connection);
}
}
}
}
else {
Node sourceNode;
Role sourceRole;
if (sourceEnd instanceof Edge) {
sourceNode = QVTscheduleUtil.getTargetNode((Edge) sourceEnd);
sourceRole = ((Edge)sourceEnd).getEdgeRole();
}
else {
sourceNode = (Node) sourceEnd;
sourceRole = ((Node)sourceEnd).getNodeRole();
}
if (!sourceRole.isChecked()) { //sourceRole.isNew() || sourceRole.isLoaded()) {
appendEdge(sourceNode, connection, connection);
}
}
}
for (@NonNull ConnectionEnd target : connection.getTargetEnds()) {
ConnectionRole connectionRole = connection.getTargetRole(target);
assert connectionRole != null;
Region targetRegion = rootRegion.getNormalizedRegion(QVTscheduleUtil.getOwningRegion(target));
if (targetRegion != null) {
Iterable<@NonNull MappingPartition> partitions = null;
if (targetRegion instanceof MappingRegion) {
partitions = QVTscheduleUtil.getMappingPartitions((MappingRegion)targetRegion);
}
if (partitions != null) {
for (@NonNull Partition targetPartition : partitions) {
ConnectionRole targetConnectionRole = connectionRole;
Role role;
Node targetGraphNode;
if (target instanceof Node) {
Node targetNode = (Node)target;
role = targetPartition.getRole(targetNode);
targetGraphNode = targetNode;
if (!targetPartition.isHead(targetNode)) {
targetConnectionRole = ClassUtil.nonNullState(ConnectionRole.PREFERRED_NODE);
}
}
else {
@NonNull NavigableEdge targetEdge = (NavigableEdge)target;
role = targetPartition.getRole(targetEdge);
targetGraphNode = QVTscheduleUtil.getTargetNode(targetEdge);
}
if ((role != null) && role.isOld()) {
setScope(targetPartition);
assert targetConnectionRole != null;
appendEdge(connection, targetConnectionRole, targetGraphNode);
}
}
}
}
}
setScope(null);
}
else { // Node-to-Node within Region within RootRegion
appendNode(connection);
for (@NonNull Node sourceNode : connection.getSourceNodes()) {
appendEdge(sourceNode, connection, connection);
}
for (@NonNull ConnectionEnd target : connection.getTargetEnds()) {
ConnectionRole role = connection.getTargetRole(target);
assert role != null;
if (target instanceof Node) {
appendEdge(connection, role, (Node)target);
}
else {
appendEdge(connection, role, QVTscheduleUtil.getTargetNode((NavigableEdge)target));
}
}
}
return null;
}
}
protected boolean hasPartitions = false;
protected @Nullable Partition partition = null;
protected ToGraphPartitionVisitor(@NonNull GraphStringBuilder context) {
super(context);
}
@Override
protected @NonNull String getColor(@NonNull GraphElement element) {
Role role = getGraphRole(element);
if (role != null) {
return QVTscheduleUtil.getColor(role);
}
return super.getColor(element);
}
protected @Nullable Role getGraphRole(GraphElement element) {
Role role = null;
if (element instanceof Node) {
role = partition != null ? partition.getRole((Node)element) : ((Node)element).getNodeRole();
}
else if (element instanceof Edge) {
role = partition != null ? partition.getRole((Edge)element) : ((Edge)element).getEdgeRole();
}
return role;
}
@Override
protected @NonNull String getLabel(@NonNull GraphNode graphNode) {
Role role = getGraphRole(graphNode);
if (role == Role.CONSTANT_SUCCESS_FALSE) {
return " false \nBoolean";
}
else if (role == Role.CONSTANT_SUCCESS_TRUE) {
return " true \nBoolean";
}
return super.getLabel(graphNode);
}
@Override
protected @Nullable String getShape(@NonNull GraphNode graphNode) {
Role role = getGraphRole(graphNode);
if ((role == Role.CONSTANT_SUCCESS_FALSE) || (role == Role.CONSTANT_SUCCESS_TRUE)) {
return null; // rectangle
}
return super.getShape(graphNode);
}
@Override
protected @Nullable String getStyle(@NonNull GraphNode graphNode) {
Role role = getGraphRole(graphNode);
if ((role == Role.CONSTANT_SUCCESS_FALSE) || (role == Role.CONSTANT_SUCCESS_TRUE)) {
return "rounded";
}
return super.getStyle(graphNode);
}
@Override
protected boolean isHead(@NonNull GraphNode graphNode) {
if (partition != null) {
return partition.isHead((Node)graphNode);
}
else {
return ((Node)graphNode).isHead();
}
}
protected abstract void setScope(@Nullable Object scopeObject);
protected abstract void showPartitionInternals(@NonNull Partition partition);
protected abstract void showRegionInternals(@NonNull Region region);
protected void showRootRegionInternals(@NonNull RootRegion rootRegion) {
RootPartition rootPartition = rootRegion.getOwnedRootPartition();
if (rootPartition == null) {
for (@NonNull Region region : QVTscheduleUtil.getActiveRegions(rootRegion)) {
region.accept(this);
}
}
else {
rootPartition.accept(this);
}
}
@Override
public @Nullable String visitBasicPartition(@NonNull BasicPartition basicPartition) {
if (basicPartition.getOwningMergedPartition() == null) {
super.visitBasicPartition(basicPartition);
}
return null;
}
@Override
public @Nullable String visitCyclicPartition(@NonNull CyclicPartition cyclicPartition) {
for (@NonNull MappingPartition partition : QVTscheduleUtil.getOwnedMappingPartitions(cyclicPartition)) {
setScope(partition);
partition.accept(this);
}
return null;
}
@Override
public @Nullable String visitEdge(@NonNull Edge edge) {
appendEdge(edge.getEdgeSource(), edge, edge.getEdgeTarget());
return null;
}
@Override
public @Nullable String visitNavigableEdge(@NonNull NavigableEdge navigableEdge) {
if (!navigableEdge.isSecondary()) {
return super.visitNavigableEdge(navigableEdge);
}
else {
return null; // No need to draw edges twice.
}
}
@Override
public @Nullable String visitNode(@NonNull Node object) {
appendNode(object);
return null;
}
@Override
public @Nullable String visitPartition(@NonNull Partition partition) {
assert this.partition == null;
try {
this.partition = partition;
// String label = partition.getName();
// String passesText = partition.getPassesText();
// if (passesText != null) {
// label = label + "\\n " + passesText;
// }
// context.setLabel(label);
context.setColor(QVTscheduleConstants.REGION_COLOR);
showPartitionInternals(partition);
return null;
}
finally {
this.partition = null;
}
}
@Override
public @Nullable String visitRootPartition(@NonNull RootPartition rootPartition) {
for (@NonNull MappingPartition partition : QVTscheduleUtil.getOwnedMappingPartitions(rootPartition)) {
setScope(partition);
partition.accept(this);
}
return null;
}
@Override
public @Nullable String visitRegion(@NonNull Region region) {
context.setLabel(region.getName());
context.setColor(QVTscheduleConstants.REGION_COLOR);
showRegionInternals(region);
return null;
}
@Override
public @Nullable String visitRootRegion(@NonNull RootRegion rootRegion) {
RootPartition rootPartition = rootRegion.getOwnedRootPartition();
hasPartitions = rootPartition != null;
context.setLabel(rootRegion.getName());
context.setColor(QVTscheduleConstants.REGION_COLOR);
context.pushCluster();
for (@NonNull OperationRegion region : QVTscheduleUtil.getOwnedOperationRegions(QVTscheduleUtil.getOwningScheduleModel(rootRegion))) {
region.accept(this);
}
// LoadingRegion loadingRegion = rootRegion.getOwnedLoadingRegion();
// if (loadingRegion != null) {
// loadingRegion.accept(this);
// }
showRootRegionInternals(rootRegion);
for (@NonNull Node node : QVTscheduleUtil.getOwnedNodes(rootRegion)) {
appendNode(node);
}
for (@NonNull Edge edge : QVTscheduleUtil.getOwnedEdges(rootRegion)) {
appendEdge(edge.getEdgeSource(), edge, edge.getEdgeTarget());
}
for (@NonNull Connection connection : QVTscheduleUtil.getOwnedConnections(rootRegion)) {
connection.accept(this);
}
context.popCluster();
return null;
}
}