/******************************************************************************* * Copyright (c) 2012 Association for Decentralized Information Management in * Industry THTH ry. * 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: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.modeling.flags; import gnu.trove.map.hash.THashMap; import gnu.trove.set.hash.THashSet; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.Statement; import org.simantics.db.WriteGraph; import org.simantics.db.common.request.IndexRoot; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.common.utils.OrderedSetUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.diagram.content.ConnectionUtil; import org.simantics.diagram.stubs.DiagramResource; import org.simantics.layer0.Layer0; import org.simantics.modeling.ModelingResources; import org.simantics.scl.commands.Commands; import org.simantics.scl.runtime.tuple.Tuple2; import org.simantics.structural.stubs.StructuralResource2; public class MergeFlags { private static class CP { public final Resource component; public final Resource connectionPoint; public CP(Resource component, Resource connectionPoint) { super(); this.component = component; this.connectionPoint = connectionPoint; } @Override public int hashCode() { return component.hashCode() + 31 * connectionPoint.hashCode(); } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; CP other = (CP) obj; return component.equals(other.component) && connectionPoint.equals(other.connectionPoint); } } public static String validateForMerge(ReadGraph g, List flags) throws DatabaseException { if(flags.size() <= 1) return "At least two flags must be chosen."; DiagramResource DIA = DiagramResource.getInstance(g); StructuralResource2 STR = StructuralResource2.getInstance(g); for(Resource flag : flags) if(!g.hasStatement(flag, DIA.FlagIsJoinedBy)) return "All flags are not joined to other flags."; List connectors = getPossibleRelated(g, flags, DIA.Flag_ConnectionPoint); for(Resource connector : connectors) { if(connector == null) return "All flags are not connected"; } List connections = getConnection(g, flags, connectors); for(Resource connection : connections) { if(connection == null) return "Invalid flag. Didn't find configuration connection."; } THashSet uniqueConnections = new THashSet(connections.size()); for(Resource connection : connections) { uniqueConnections.add(connection); } if(uniqueConnections.size() == 1) return null; Iterator it = uniqueConnections.iterator(); THashSet cps = getConnectionPoints(g, STR, it.next()); while(it.hasNext()) { cps.retainAll(getConnectionPoints(g, STR, it.next())); if(cps.isEmpty()) return "Flags are not connected to a common terminal."; } return null; } private static THashSet getConnectionPoints(ReadGraph g, StructuralResource2 STR, Resource connection) throws DatabaseException { THashSet result = new THashSet(); for(Statement stat : g.getStatements(connection, STR.Connects)) result.add(new CP(stat.getObject(), g.getInverse(stat.getPredicate()))); return result; } /** * Merges all flags in the given list to one or two flags. * @param g * @param flags to join * @return Error message or empty string if the operation succeeded. */ public static String merge(WriteGraph g, List flags) throws DatabaseException { return (String)Commands.get(g, "Simantics/Flag/mergeFlags").execute(g, g.syncRequest(new IndexRoot(flags.get(0))), flags); } public static String mergeWithoutMetadata(WriteGraph g, List flags) throws DatabaseException { THashMap> groups = new THashMap>(); DiagramResource DIA = DiagramResource.getInstance(g); StructuralResource2 STR = StructuralResource2.getInstance(g); for(Resource flag : flags) { Resource connector = g.getSingleObject(flag, DIA.Flag_ConnectionPoint); Resource connection = null; for(Resource temp : g.getObjects(connector, STR.Connects)) if(!temp.equals(flag)) { connection = temp; break; } if(connection == null) continue; Resource flagType = g.getSingleObject(flag, DIA.HasFlagType); Resource connectionType = g.getPossibleObject(connection, STR.HasConnectionType); Tuple2 tuple = new Tuple2(flagType, connectionType); ArrayList group = groups.get(tuple); if(group == null) { group = new ArrayList(); groups.put(tuple, group); } group.add(flag); } String errorMessage = ""; for(ArrayList group : groups.values()) { if(group.size() > 1) { String temp = mergeAux(g, group); if(temp != null) errorMessage = temp; } } return errorMessage; } /** * Merges all flags in the given list to the first flag of the list. * @param g * @param flags to join * @return Error message or null if the operation succeeded. */ private static String mergeAux(WriteGraph g, List flags) throws DatabaseException { if(flags.size() <= 1) return null; // Nothing to do DiagramResource DIA = DiagramResource.getInstance(g); StructuralResource2 STR = StructuralResource2.getInstance(g); // Find connectors List connectors = getPossibleRelated(g, flags, DIA.Flag_ConnectionPoint); for(Resource connector : connectors) { if(connector == null) return "All flags are not connected"; } // Find configuration connections List connections = getConnection(g, flags, connectors); for(Resource connection : connections) { if(connection == null) return "Invalid flag. Didn't find configuration connection."; } // Choose canonical flag and connection where other flags are merged to Resource canonicalFlag = flags.get(0); Resource canonicalConnection = connections.get(0); // Do the merging for(int i=1;i uniqueConnections = new THashSet(connections.size()); for(int i=1;i getConnection(ReadGraph g, List flags, List connectors) throws DatabaseException { ArrayList result = new ArrayList(flags.size()); for(int i=0;i getPossibleRelated(ReadGraph g, List subjects, Resource relation) throws DatabaseException { ArrayList result = new ArrayList(subjects.size()); for(int i=0;i flags) throws DatabaseException { DiagramResource DIA = DiagramResource.getInstance(graph); StructuralResource2 STR = StructuralResource2.getInstance(graph); THashSet connectionSet = new THashSet(); for(Resource flag : flags) { for(Resource connector : graph.getObjects(flag, STR.IsConnectedTo)) for(Resource connection : graph.getObjects(connector, STR.Connects)) if(!connection.equals(flag)) connectionSet.add(connection); } for(Resource connection : connectionSet.toArray(new Resource[connectionSet.size()])) { for(Resource connector : graph.getObjects(connection, STR.IsConnectedTo)) for(Statement stat : graph.getStatements(connector, STR.Connects)) if(!stat.getObject().equals(connection)) for(Resource connector2 : graph.getObjects(stat.getObject(), graph.getInverse(stat.getPredicate()))) if(!connector2.equals(connector)) for(Resource connection2 : graph.getObjects(connector2, STR.Connects)) if(graph.isInstanceOf(connection2, DIA.Connection)) connectionSet.add(connection2); } THashSet visited = new THashSet(flags); for(Resource connection : connectionSet) { visited.add(connection); for(Resource connector : graph.getObjects(connection, STR.IsConnectedTo)) for(Resource flag : graph.getObjects(connector, STR.Connects)) if(visited.add(flag) && graph.isInstanceOf(flag, DIA.Flag) && graph.hasStatement(flag, DIA.FlagIsJoinedBy)) flags.add(flag); } } public static void collectFlagGroupsInComposite(ReadGraph g, Resource composite, ArrayList> groups) throws DatabaseException { DiagramResource DIA = DiagramResource.getInstance(g); ModelingResources MOD = ModelingResources.getInstance(g); Layer0 L0 = Layer0.getInstance(g); Resource diagram = g.getPossibleObject(composite, MOD.CompositeToDiagram); if(diagram == null) return; THashSet flags = new THashSet(); for(Resource element : g.getObjects(diagram, L0.ConsistsOf)) if(g.isInstanceOf(element, DIA.Flag) && g.hasStatement(element, DIA.FlagIsJoinedBy)) flags.add(element); for(Resource flag : flags.toArray(new Resource[flags.size()])) if(flags.contains(flag)) { ArrayList group = new ArrayList(); group.add(flag); expandFlagSet(g, group); flags.removeAll(group); if(group.size() > 1) groups.add(group); } } public static void expandCompositeSet(ReadGraph g, THashSet composites) throws DatabaseException { for(Resource composite : composites.toArray(new Resource[composites.size()])) expandCompositeSet(g, composite, composites); } private static void expandCompositeSet(ReadGraph g, Resource composite, THashSet composites) throws DatabaseException { Layer0 L0 = Layer0.getInstance(g); StructuralResource2 STR = StructuralResource2.getInstance(g); for(Resource child : g.getObjects(composite, L0.ConsistsOf)) if(g.isInstanceOf(child, STR.Composite)) if(composites.add(child)) expandCompositeSet(g, child, composites); } public static String mergeFlags (WriteGraph graph, Resource diagram ) throws DatabaseException { ArrayList> groups = new ArrayList>(); MergeFlags.collectFlagGroupsInComposite(graph, diagram, groups); for(ArrayList group : groups) { MergeFlags.merge(graph, group); } return "Merged flags in diagram resource: " + diagram.toString() + " and name: " + NameUtils.getSafeName(graph, diagram); } public static void expandFlags(WriteGraph graph, Resource diagram) throws DatabaseException { ArrayList groups = new ArrayList(); ExpandFlags.collectGroupedFlags(graph, diagram, groups); for(Resource group : groups) { ExpandFlags.expandFlag(graph, group); } } }