From: Tuukka Lehtonen Date: Wed, 7 Sep 2016 12:50:57 +0000 (+0300) Subject: Sync git svn branch with SVN repository r33176. X-Git-Tag: v1.25.0~132 X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=commitdiff_plain;h=c78854f7886d52b5375e11b3d6d8daacb12c287e Sync git svn branch with SVN repository r33176. refs #6677 --- diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/flag/FlagUtil.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/flag/FlagUtil.java index 6f884e06a..27dc9e307 100644 --- a/bundles/org.simantics.diagram/src/org/simantics/diagram/flag/FlagUtil.java +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/flag/FlagUtil.java @@ -247,14 +247,25 @@ public final class FlagUtil { RemoverUtil.remove(graph, flag); } + /** + * @param graph + * @param flag + * @return true only if the specified flag is joined only + * within the single diagram it resides in + * @throws DatabaseException + */ public static boolean isJoinedInSingleDiagram(ReadGraph graph, Resource flag) throws DatabaseException { - DiagramResource DIA = DiagramResource.getInstance(graph); - Resource counterpart = getPossibleCounterpart(graph, flag); - if (counterpart == null) + Collection counterparts = getCounterparts(graph, flag); + if (counterparts.isEmpty()) return false; - return !Collections.disjoint( - OrderedSetUtils.getOwnerLists(graph, flag, DIA.Diagram), - OrderedSetUtils.getOwnerLists(graph, counterpart, DIA.Diagram)); + DiagramResource DIA = DiagramResource.getInstance(graph); + Collection flagDiagrams = OrderedSetUtils.getOwnerLists(graph, flag, DIA.Diagram); + for (Resource counterpart : counterparts) { + if (Collections.disjoint(flagDiagrams, + OrderedSetUtils.getOwnerLists(graph, counterpart, DIA.Diagram))) + return false; + } + return true; } public static boolean isJoinedBetweenDiagrams(ReadGraph graph, Resource flag) throws DatabaseException { diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/flag/Joiner.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/flag/Joiner.java index cc02b7638..490a770df 100644 --- a/bundles/org.simantics.diagram/src/org/simantics/diagram/flag/Joiner.java +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/flag/Joiner.java @@ -1,6 +1,5 @@ package org.simantics.diagram.flag; -import java.util.ArrayDeque; import java.util.Collection; import java.util.HashSet; import java.util.Set; @@ -33,127 +32,157 @@ public class Joiner { StructuralResource2 STR; ModelingResources MOD; + ConnectionUtil cu; + public Joiner(ReadGraph graph) { this.L0 = Layer0.getInstance(graph); this.DIA = DiagramResource.getInstance(graph); this.STR = StructuralResource2.getInstance(graph); this.MOD = ModelingResources.getInstance(graph); + this.cu = new ConnectionUtil(graph); } public void joinLocal(WriteGraph graph, Collection flags) throws DatabaseException { - ConnectionUtil cu = new ConnectionUtil(graph); - Set visited = new HashSet(); - ArrayDeque todo = new ArrayDeque(flags); - while (!todo.isEmpty()) { - Resource flag1 = todo.poll(); - Resource flag2 = FlagUtil.getPossibleCounterpart(graph, flag1); - if (flag2 == null || !visited.add(flag1) || !visited.add(flag2)) - continue; - - Type type1 = FlagUtil.getFlagType(graph, flag1); - Type type2 = FlagUtil.getFlagType(graph, flag2); - - Resource connector1 = null; - Resource connector2 = null; - - Resource connection1 = null; - Resource connection2 = null; - - // #7781: prevent joining of flags where one of them or both are - // have no connections to them, i.e. are disconnected. - // First ensure that both flags are connected to something, - // even considering joining them. - for (Resource connector : graph.getObjects(flag1, STR.IsConnectedTo)) { - connector1 = graph.getPossibleObject(connector, DIA.AreConnected); - connection1 = ConnectionUtil.getConnection(graph, connector1); + // Only those flags that are known to be removed during the joining of + // two flags are added to this set to prevent processing them multiple times. + Set removed = new HashSet(); + for (Resource flag1 : flags) { + Collection flag1Counterparts = FlagUtil.getCounterparts(graph, flag1); + for (Resource flag2 : flag1Counterparts) { + boolean flag1Removed = FlagUtil.countCounterparts(graph, flag1) <= 1; + boolean flag2Removed = FlagUtil.countCounterparts(graph, flag2) <= 1; + if (flag1Removed && !removed.add(flag1)) + continue; + if (flag2Removed && !removed.add(flag2)) + continue; + boolean switchFlags = !flag1Removed && flag2Removed; + Resource f1 = switchFlags ? flag2 : flag1; + Resource f2 = switchFlags ? flag1 : flag2; + joinFlagPair(graph, f1, f2); } - for (Resource connector : graph.getObjects(flag2, STR.IsConnectedTo)) { - connector2 = graph.getPossibleObject(connector, DIA.AreConnected); - connection2 = ConnectionUtil.getConnection(graph, connector2); - } - if (connection1 == null || connector1 == null || connection2 == null || connector2 == null) - continue; - - // Disconnect flags from their respective edges - // This code relies on the fact that flag terminals are - // functional and can only be connected once. This implies - // that their :DIA.Connectors cannot have more than one - // AreConnected relation. + } + } + + private boolean joinFlagPair(WriteGraph graph, Resource flag1, Resource flag2) throws DatabaseException { + Type type1 = FlagUtil.getFlagType(graph, flag1); + Type type2 = FlagUtil.getFlagType(graph, flag2); + + Resource connector1 = null; + Resource connector2 = null; + + Resource connection1 = null; + Resource connection2 = null; + + // #7781: prevent joining of flags where one of them or both + // have no connections to them, i.e. are disconnected. + // First ensure that both flags are connected to something, + // even considering joining them. + for (Resource connector : graph.getObjects(flag1, STR.IsConnectedTo)) { + connector1 = graph.getPossibleObject(connector, DIA.AreConnected); + connection1 = ConnectionUtil.getConnection(graph, connector1); + } + for (Resource connector : graph.getObjects(flag2, STR.IsConnectedTo)) { + connector2 = graph.getPossibleObject(connector, DIA.AreConnected); + connection2 = ConnectionUtil.getConnection(graph, connector2); + } + if (connection1 == null || connector1 == null || connection2 == null || connector2 == null) + return false; + + // If a flag has more than 1 counterpart it must not be + // removed because it is a merged flag that has multiple + // connection joins attached to it. + boolean removeFlag1 = FlagUtil.countCounterparts(graph, flag1) <= 1; + boolean removeFlag2 = FlagUtil.countCounterparts(graph, flag2) <= 1; + + // Disconnect flags from their respective edges + // This code relies on the fact that flag terminals are + // functional and can only be connected once. This implies + // that their :DIA.Connectors cannot have more than one + // AreConnected relation. + if (removeFlag1) { for (Resource connector : graph.getObjects(flag1, STR.IsConnectedTo)) { - connector1 = graph.getPossibleObject(connector, DIA.AreConnected); + connector1 = graph.getSingleObject(connector, DIA.AreConnected); connection1 = ConnectionUtil.getConnection(graph, connector1); cu.removeConnectionPart(connector); } + } + if (removeFlag2) { for (Resource connector : graph.getObjects(flag2, STR.IsConnectedTo)) { - connector2 = graph.getPossibleObject(connector, DIA.AreConnected); + connector2 = graph.getSingleObject(connector, DIA.AreConnected); connection2 = ConnectionUtil.getConnection(graph, connector2); cu.removeConnectionPart(connector); } + } - // Decide which connection to remove. The strategy is: - // * always keep the connection that has an ElementToComponent relation. - // * if there are no ElementToComponent relations, keep the connection on the OutputFlag side. - // * if flag type information is not available, keep connection1. - Resource connectionToKeep = connection1; - Resource connectionToRemove = connection2; - Resource hasElementToComponent1 = graph.getPossibleObject(connection1, MOD.ElementToComponent); - Resource hasElementToComponent2 = graph.getPossibleObject(connection2, MOD.ElementToComponent); - if (hasElementToComponent1 != null && hasElementToComponent2 != null) - throw new UnsupportedOperationException("Both flag are connected with connections that have mapped components, can't decide which connection to remove in join operation"); - if (hasElementToComponent2 != null - || (type1 != Type.Out && type2 == Type.Out)) { - connectionToKeep = connection2; - connectionToRemove = connection1; - } + // Decide which connection to remove. The strategy is: + // * always keep the connection that has an ElementToComponent relation. + // * if there are no ElementToComponent relations, keep the connection on the OutputFlag side. + // * if flag type information is not available, keep connection1. + Resource connectionToKeep = connection1; + Resource connectionToRemove = connection2; + Resource hasElementToComponent1 = graph.getPossibleObject(connection1, MOD.ElementToComponent); + Resource hasElementToComponent2 = graph.getPossibleObject(connection2, MOD.ElementToComponent); + if (hasElementToComponent1 != null && hasElementToComponent2 != null) + throw new UnsupportedOperationException("Both flag are connected with connections that have mapped components, can't decide which connection to remove in join operation"); + if (hasElementToComponent2 != null + || (type1 != Type.Out && type2 == Type.Out)) { + connectionToKeep = connection2; + connectionToRemove = connection1; + } - // Remove connection join and flags + // Remove connection join and flags when necessary + if (removeFlag1) for (Resource diagram : OrderedSetUtils.getOwnerLists(graph, flag1, DIA.Diagram)) OrderedSetUtils.remove(graph, diagram, flag1); + if (removeFlag2) for (Resource diagram : OrderedSetUtils.getOwnerLists(graph, flag2, DIA.Diagram)) OrderedSetUtils.remove(graph, diagram, flag2); - FlagUtil.disconnectFlag(graph, flag1); - double[] transform1 = graph.getRelatedValue(flag1, DIA.HasTransform, Bindings.DOUBLE_ARRAY); - double[] transform2 = graph.getRelatedValue(flag2, DIA.HasTransform, Bindings.DOUBLE_ARRAY); + FlagUtil.disconnectFlag(graph, flag1); + double[] transform1 = graph.getRelatedValue(flag1, DIA.HasTransform, Bindings.DOUBLE_ARRAY); + double[] transform2 = graph.getRelatedValue(flag2, DIA.HasTransform, Bindings.DOUBLE_ARRAY); + if (removeFlag1) RemoverUtil.remove(graph, flag1); + if (removeFlag2) RemoverUtil.remove(graph, flag2); - // Move connector from connection to remove to other connection - for(Statement connectorStat : graph.getStatements(connectionToRemove, DIA.HasConnector)) { - graph.deny(connectorStat); - graph.claim(connectionToKeep, connectorStat.getPredicate(), connectorStat.getObject()); - } - for(Resource node : graph.getObjects(connectionToRemove, DIA.HasInteriorRouteNode)) { - graph.deny(node, DIA.HasInteriorRouteNode_Inverse, connectionToRemove); - graph.claim(node, DIA.HasInteriorRouteNode_Inverse, connectionToKeep); - } + // Move connector from connection to remove to other connection + for(Statement connectorStat : graph.getStatements(connectionToRemove, DIA.HasConnector)) { + graph.deny(connectorStat); + graph.claim(connectionToKeep, connectorStat.getPredicate(), connectorStat.getObject()); + } + for(Resource node : graph.getObjects(connectionToRemove, DIA.HasInteriorRouteNode)) { + graph.deny(node, DIA.HasInteriorRouteNode_Inverse, connectionToRemove); + graph.claim(node, DIA.HasInteriorRouteNode_Inverse, connectionToKeep); + } - // Remove obsolete connection - cu.removeConnection(connectionToRemove); - - // Reconnect respective edges - if(graph.isInstanceOf(connector1, DIA.RouteLine) && graph.isInstanceOf(connector2, DIA.RouteLine) - && graph.getRelatedValue(connector1, DIA.IsHorizontal) == graph.getRelatedValue(connector2, DIA.IsHorizontal)) { - boolean horizontal = graph.getRelatedValue(connector1, DIA.IsHorizontal); - - double position; - if(horizontal) - position = 0.5 * (transform1[4] + transform2[4]); - else - position = 0.5 * (transform1[5] + transform2[5]); - - Resource intermediateRouteLine = graph.newResource(); - graph.claim(intermediateRouteLine, L0.InstanceOf, DIA.RouteLine); - graph.claimLiteral(intermediateRouteLine, DIA.IsHorizontal, !horizontal); - graph.claimLiteral(intermediateRouteLine, DIA.HasPosition, position); - graph.claim(connectionToKeep, DIA.HasInteriorRouteNode, intermediateRouteLine); - graph.claim(connector1, DIA.AreConnected, intermediateRouteLine); - graph.claim(connector2, DIA.AreConnected, intermediateRouteLine); - } + // Remove obsolete connection + cu.removeConnection(connectionToRemove); + + // Reconnect respective edges + if(graph.isInstanceOf(connector1, DIA.RouteLine) && graph.isInstanceOf(connector2, DIA.RouteLine) + && graph.getRelatedValue(connector1, DIA.IsHorizontal) == graph.getRelatedValue(connector2, DIA.IsHorizontal)) { + boolean horizontal = graph.getRelatedValue(connector1, DIA.IsHorizontal); + + double position; + if(horizontal) + position = 0.5 * (transform1[4] + transform2[4]); else - graph.claim(connector1, DIA.AreConnected, connector2); + position = 0.5 * (transform1[5] + transform2[5]); + + Resource intermediateRouteLine = graph.newResource(); + graph.claim(intermediateRouteLine, L0.InstanceOf, DIA.RouteLine); + graph.claimLiteral(intermediateRouteLine, DIA.IsHorizontal, !horizontal); + graph.claimLiteral(intermediateRouteLine, DIA.HasPosition, position); + graph.claim(connectionToKeep, DIA.HasInteriorRouteNode, intermediateRouteLine); + graph.claim(connector1, DIA.AreConnected, intermediateRouteLine); + graph.claim(connector2, DIA.AreConnected, intermediateRouteLine); } + else + graph.claim(connector1, DIA.AreConnected, connector2); + + return true; } - + public static void joinFlagsLocal(WriteGraph graph, Collection flags) throws DatabaseException { new Joiner(graph).joinLocal(graph, flags); } diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/handler/ConnectionSplitAndJoin.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/handler/ConnectionSplitAndJoin.java index 9e7a1637e..d46c42732 100644 --- a/bundles/org.simantics.diagram/src/org/simantics/diagram/handler/ConnectionSplitAndJoin.java +++ b/bundles/org.simantics.diagram/src/org/simantics/diagram/handler/ConnectionSplitAndJoin.java @@ -29,6 +29,7 @@ import org.simantics.db.Session; import org.simantics.db.WriteGraph; import org.simantics.db.common.request.IndexRoot; import org.simantics.db.common.request.WriteRequest; +import org.simantics.db.common.utils.OrderedSetUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.diagram.content.ConnectionUtil; import org.simantics.diagram.content.EdgeResource; @@ -150,13 +151,20 @@ public class ConnectionSplitAndJoin extends DynamicMenuContribution { Resource r = AdaptionUtils.adaptToSingle(s, Resource.class); if (r == null || !graph.isInstanceOf(r, DIA.Flag)) return Collections.emptyList(); - Resource counterpart = FlagUtil.getPossibleCounterpart(graph, r); - if (counterpart == null) + if (!isConnectedToSomething(graph, r)) return Collections.emptyList(); - if (!FlagUtil.isJoinedInSingleDiagram(graph, r)) - return Collections.emptyList(); - if (!isConnectedToSomething(graph, r) || !isConnectedToSomething(graph, counterpart)) + Collection counterparts = FlagUtil.getCounterparts(graph, r); + if (counterparts.isEmpty()) return Collections.emptyList(); + Collection flagDiagrams = OrderedSetUtils.getOwnerLists(graph, r, DIA.Diagram); + for (Resource counterpart : counterparts) { + boolean joinedWithinSingleDiagram = !Collections.disjoint(flagDiagrams, + OrderedSetUtils.getOwnerLists(graph, counterpart, DIA.Diagram)); + if (!joinedWithinSingleDiagram) + return Collections.emptyList(); + if (!isConnectedToSomething(graph, counterpart)) + return Collections.emptyList(); + } result.add(r); } return result;